✅ test(people): add unit test for people-related components

This commit is contained in:
2026-02-17 15:50:48 +01:00
parent 07ca70bc9b
commit e5ddf93ddb
4 changed files with 209 additions and 5 deletions
@@ -0,0 +1,43 @@
import React from 'react'
import { render, screen, fireEvent } from '@testing-library/react'
import { vi } from 'vitest'
import EmployeeDescriptionDialog, { EmployeeDescription } from './index'
describe('EmployeeDescriptionDialog', () => {
const base: EmployeeDescription = {
title: 'Sir Tester',
position: 'Tester General',
image: '/images/tester.jpg',
body: ['First paragraph', 'Second paragraph'],
captions: ['Caption A', 'Caption B'],
}
it('renders title, position, image and body paragraphs', () => {
render(<EmployeeDescriptionDialog open description={base} />)
expect(screen.getByText(base.title)).toBeInTheDocument()
expect(screen.getByText(base.position!)).toBeInTheDocument()
const img = screen.getByAltText(base.title) as HTMLImageElement
expect(img).toBeInTheDocument()
expect(img.src).toContain(base.image)
expect(screen.getByText('First paragraph')).toBeInTheDocument()
expect(screen.getByText('Second paragraph')).toBeInTheDocument()
})
it('renders captions when provided', () => {
render(<EmployeeDescriptionDialog open description={base} />)
expect(screen.getByText('Caption A')).toBeInTheDocument()
expect(screen.getByText('Caption B')).toBeInTheDocument()
})
it('calls onClose when close button is clicked', () => {
const handleClose = vi.fn()
render(<EmployeeDescriptionDialog open description={base} onClose={handleClose} />)
const button = screen.getByLabelText('close')
fireEvent.click(button)
expect(handleClose).toHaveBeenCalledTimes(1)
})
})
@@ -0,0 +1,55 @@
import { render, screen, fireEvent } from '@testing-library/react'
import { vi } from 'vitest'
import EmplyeeCard from './index'
describe('EmplyeeCard', () => {
const name = 'John Doe'
const image = '/images/john.jpg'
const position = 'Blacksmith'
it('renders name, image and optional position', () => {
render(<EmplyeeCard name={name} image={image} position={position} />)
expect(screen.getByText(name)).toBeInTheDocument()
expect(screen.getByText(position)).toBeInTheDocument()
const img = screen.getByAltText(`${name} image`) as HTMLImageElement
expect(img).toBeInTheDocument()
expect(img.src).toContain(image)
})
it('calls onClick with (event, description) payload', () => {
const description = { body: ['this is a description for John Doe'] }
const handleClick = vi.fn()
render(<EmplyeeCard name={name} image={image} position={position} description={description} onClick={handleClick} />)
fireEvent.click(screen.getByText(name))
expect(handleClick).toHaveBeenCalledTimes(1)
expect(handleClick).toHaveBeenCalledWith(expect.any(Object), {
title: name,
image: image,
position: position,
...description,
})
})
it('calls onClick with the fields set in the description', () => {
const description = {
title: 'Jane Doe',
position: 'Barber',
image: '/images/jane.jpg',
body: ['this is a description for Jane Doe'],
}
const handleClick = vi.fn()
render(<EmplyeeCard name={name} image={image} position={position} description={description} onClick={handleClick} />)
fireEvent.click(screen.getByText(name))
expect(handleClick).toHaveBeenCalledTimes(1)
expect(handleClick).toHaveBeenCalledWith(expect.any(Object), {
...description,
})
})
})
@@ -0,0 +1,81 @@
import React from 'react'
import { render, screen, fireEvent } from '@testing-library/react'
import { vi } from 'vitest'
import 'components/molecules/EmplyeeCard/index.js'
import EmplyeeStack from './index'
// Mock EmplyeeCard to make click handling deterministic in tests
vi.mock('components/molecules/EmplyeeCard/index.js', () => ({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
EmplyeeCard: (props: any) => (
<div
data-testid="mock-card"
onClick={e => props.onClick?.(e, { title: props.name, image: props.image, position: props.position, ...(props.description || {}) })}>
<img alt={`${props.name} image`} src={props.image} />
{props.name}
</div>
),
}))
describe('EmplyeeStack', () => {
const items = [
{ name: 'Alice', image: '/images/alice.jpg', position: 'Armorer' },
{ name: 'Bob', image: '/images/bob.jpg', position: 'Fletcher' },
{ name: 'Charlie', image: '/images/charlie.jpg', position: 'Scribe' },
]
it('renders all provided cards (up to maxVisible)', () => {
render(<EmplyeeStack items={items} />)
const imgs = screen.getAllByRole('img')
expect(imgs).toHaveLength(items.length)
expect(imgs[0]).toHaveAttribute('alt', `${items[0].name} image`)
})
it('renders provided cards up to maxVisible', () => {
render(<EmplyeeStack items={items} maxVisible={2} />)
const imgs = screen.getAllByRole('img')
expect(imgs).toHaveLength(2)
})
it('rotates the top card to the back on click', () => {
render(<EmplyeeStack items={items} />)
// initial order: Alice, Bob, Charlie
let imgs = screen.getAllByRole('img')
expect(imgs[0]).toHaveAttribute('alt', 'Alice image')
// clicking the shuffle IconButton rotates the deck
const buttons = screen.getAllByRole('button')
fireEvent.click(buttons[buttons.length - 1])
imgs = screen.getAllByRole('img')
// after rotation: Bob, Charlie, Alice
expect(imgs[0]).toHaveAttribute('alt', 'Bob image')
expect(imgs[1]).toHaveAttribute('alt', 'Charlie image')
expect(imgs[2]).toHaveAttribute('alt', 'Alice image')
})
it('forwards and calls per-card onClick handlers with description payload', () => {
const handleClick = vi.fn()
const items = [
{ name: 'Alice', image: '/images/alice.jpg', position: 'Armorer', description: { body: ['A'] } },
{ name: 'Bob', image: '/images/bob.jpg', position: 'Fletcher' },
]
render(<EmplyeeStack items={items} onClick={handleClick} />)
const alice = screen.getByText('Alice')
fireEvent.click(alice)
expect(handleClick).toHaveBeenCalledTimes(1)
expect(handleClick).toHaveBeenCalledWith(expect.any(Object), {
title: 'Alice',
image: '/images/alice.jpg',
position: 'Armorer',
body: ['A'],
})
})
})
@@ -1,15 +1,40 @@
import { screen } from '@testing-library/react'
import { screen, fireEvent } from '@testing-library/react'
import 'components/molecules/EmplyeeStack/index.js'
import { renderWithRouter as render } from 'components/utils/tests/index.js'
import ProjectsPage from '.'
import ProjectsPage from './index.js'
// Mock EmplyeeStack so tests can simulate a card click opening the description dialog
vi.stubGlobal('open', vi.fn())
vi.mock('components/molecules/EmplyeeStack/index.js', () => ({
__esModule: true,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
default: (props: any) => (
<button
data-testid="mock-stack"
onClick={e => props.onClick?.(e, { title: 'Mock Person', position: 'Tester', image: '/img/mock.jpg', body: ['mock body'] })}>
MockStack
</button>
),
}))
describe('PeoplePage component', () => {
test('renders without crashing and displays the correct project titles', () => {
render(<ProjectsPage />)
// check the section titles
expect(screen.getByText('Ferantino')).toBeInTheDocument()
expect(screen.getByText('Galacino Galaci')).toBeInTheDocument()
// page title renders and stacks are present (mocked)
expect(screen.getByLabelText('page-title')).toBeInTheDocument()
const stacks = screen.getAllByTestId('mock-stack')
expect(stacks).not.toHaveLength(0)
})
test('opens description dialog when a stack item is clicked', () => {
render(<ProjectsPage />)
const [btn] = screen.getAllByTestId('mock-stack')
fireEvent.click(btn)
// dialog should show the mocked person's title
expect(screen.getByText('Mock Person')).toBeInTheDocument()
})
})