From e5ddf93ddbd2a904a62d297554e3ff132af11949 Mon Sep 17 00:00:00 2001 From: m-tartari <37861893+m-tartari@users.noreply.github.com> Date: Tue, 17 Feb 2026 15:50:48 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=85=20test(people):=20add=20unit=20test?= =?UTF-8?q?=20for=20people-related=20components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EmployeeDescription/index.test.tsx | 43 ++++++++++ .../molecules/EmplyeeCard/index.test.tsx | 55 +++++++++++++ .../molecules/EmplyeeStack/index.test.tsx | 81 +++++++++++++++++++ .../pages/PeoplePage/PeoplePage.test.tsx | 35 ++++++-- 4 files changed, 209 insertions(+), 5 deletions(-) create mode 100644 src/components/molecules/EmployeeDescription/index.test.tsx create mode 100644 src/components/molecules/EmplyeeCard/index.test.tsx create mode 100644 src/components/molecules/EmplyeeStack/index.test.tsx diff --git a/src/components/molecules/EmployeeDescription/index.test.tsx b/src/components/molecules/EmployeeDescription/index.test.tsx new file mode 100644 index 0000000..31ddbe9 --- /dev/null +++ b/src/components/molecules/EmployeeDescription/index.test.tsx @@ -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() + + 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() + + 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() + + const button = screen.getByLabelText('close') + fireEvent.click(button) + + expect(handleClose).toHaveBeenCalledTimes(1) + }) +}) diff --git a/src/components/molecules/EmplyeeCard/index.test.tsx b/src/components/molecules/EmplyeeCard/index.test.tsx new file mode 100644 index 0000000..39b73cb --- /dev/null +++ b/src/components/molecules/EmplyeeCard/index.test.tsx @@ -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() + + 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() + + 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() + + fireEvent.click(screen.getByText(name)) + + expect(handleClick).toHaveBeenCalledTimes(1) + expect(handleClick).toHaveBeenCalledWith(expect.any(Object), { + ...description, + }) + }) +}) diff --git a/src/components/molecules/EmplyeeStack/index.test.tsx b/src/components/molecules/EmplyeeStack/index.test.tsx new file mode 100644 index 0000000..eda2731 --- /dev/null +++ b/src/components/molecules/EmplyeeStack/index.test.tsx @@ -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) => ( +
props.onClick?.(e, { title: props.name, image: props.image, position: props.position, ...(props.description || {}) })}> + {`${props.name} + {props.name} +
+ ), +})) + +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() + + 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() + + const imgs = screen.getAllByRole('img') + expect(imgs).toHaveLength(2) + }) + + it('rotates the top card to the back on click', () => { + render() + + // 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() + + 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'], + }) + }) +}) diff --git a/src/components/pages/PeoplePage/PeoplePage.test.tsx b/src/components/pages/PeoplePage/PeoplePage.test.tsx index 765fc9d..a83dddc 100644 --- a/src/components/pages/PeoplePage/PeoplePage.test.tsx +++ b/src/components/pages/PeoplePage/PeoplePage.test.tsx @@ -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) => ( + + ), +})) + describe('PeoplePage component', () => { test('renders without crashing and displays the correct project titles', () => { render() - // 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() + + const [btn] = screen.getAllByTestId('mock-stack') + fireEvent.click(btn) + + // dialog should show the mocked person's title + expect(screen.getByText('Mock Person')).toBeInTheDocument() }) })