✅ test(people): add unit test for people-related components
This commit is contained in:
@@ -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 { 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.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', () => {
|
describe('PeoplePage component', () => {
|
||||||
test('renders without crashing and displays the correct project titles', () => {
|
test('renders without crashing and displays the correct project titles', () => {
|
||||||
render(<ProjectsPage />)
|
render(<ProjectsPage />)
|
||||||
|
|
||||||
// check the section titles
|
// page title renders and stacks are present (mocked)
|
||||||
expect(screen.getByText('Ferantino')).toBeInTheDocument()
|
expect(screen.getByLabelText('page-title')).toBeInTheDocument()
|
||||||
expect(screen.getByText('Galacino Galaci')).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()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user