11 — Add Tests to an Existing Module
Add comprehensive unit tests to a module that has incomplete or missing test coverage.
Covers mapper tests, component render tests, interaction tests, and a11y tests.
Context Loading
Section titled “Context Loading”Read these files before executing the prompt:
docs/dev-frontend-guides/03_MODULE_DEVELOPMENT_LIFECYCLE.md # testing sectionpackages/modules/src/m04-page-hero/m04-page-hero.test.tsx # existing test examplepackages/modules/src/{MODULE_PATH}/ # all files in the modulepackages/modules/vitest.config.ts # test configurationPrompt Template
Section titled “Prompt Template”Read the following context files first:- docs/dev-frontend-guides/03_MODULE_DEVELOPMENT_LIFECYCLE.md- packages/modules/src/m04-page-hero/m04-page-hero.test.tsx (use as test pattern reference)- packages/modules/vitest.config.ts- {MODULE_FILES — list each file in the module directory}
Now add comprehensive tests to the following module:
**Module Path:** packages/modules/src/{MODULE_PATH}/**Module Name:** {MODULE_NAME}**Module ID:** {MODULE_ID}**Test File:** packages/modules/src/{MODULE_PATH}/{PascalName}.test.tsx
**Current Test Coverage:** {DESCRIPTION — e.g., "no tests exist", "only basic render test", "mapper tests missing"}
**What to Test:**- Mapper: {YES_OR_NO}- Component rendering: {YES_OR_NO}- User interactions: {YES_OR_NO}- Accessibility (axe-core): {YES_OR_NO}
**Module Props:**{LIST_EACH_PROP_WITH_TYPE — for context on what to test}
**Specific Edge Cases to Cover:**{LIST_EDGE_CASES — e.g., empty cards array, missing optional link, null image, extremely long title}
**Mapper Input Shape (Umbraco API response):**{DESCRIBE_OR_PASTE_THE_UMBRACO_RESPONSE_STRUCTURE — so mapper tests can be accurate}
Create the test file at:packages/modules/src/{MODULE_PATH}/{PascalName}.test.tsx
Follow these conventions:- Use Vitest with @testing-library/react- Group tests with `describe` blocks: "Mapper", "Rendering", "Interactions", "Accessibility"- Test behavior, not implementation details (no testing internal state or CSS classes)- Mapper tests: valid input, missing optional fields, empty arrays, null safety, default values- Render tests: renders with valid props, conditional elements shown/hidden, responsive variants- Interaction tests: user events (click, keyboard) trigger expected behavior- A11y tests: integrate axe-core via @axe-core/react or vitest-axe- Use `screen.getByRole`, `screen.getByText`, `screen.getByLabelText` — avoid `getByTestId`- Mock data should be realistic hotel content, not placeholder text- Every test must have a clear, descriptive name explaining the expected behavior- All tests must pass with `pnpm test`Acceptance Criteria
Section titled “Acceptance Criteria”- Test file created at
packages/modules/src/{MODULE_PATH}/{PascalName}.test.tsx - Tests grouped into
describeblocks: Mapper, Rendering, Interactions (if applicable), Accessibility - Mapper tests include:
- Valid input transforms correctly to component props
- Missing optional fields result in correct defaults (not crashes)
- Empty arrays handled gracefully (e.g.,
cards: []producescards: []) - Null or undefined values in API response do not throw
- Default values applied when optional fields are absent
- Render tests include:
- Component renders without crashing with valid props
- All required content is visible (headings, text, images)
- Conditional elements shown when prop is present, hidden when absent
- Edge case: empty arrays render gracefully (empty state or no items)
- Edge case: very long text does not break layout (no overflow test needed, just no crash)
- Interaction tests include (if component is interactive):
- Click events trigger expected state changes
- Keyboard events (Enter, Space, Escape, Arrow keys) work
- Focus moves correctly during interaction
- Accessibility tests include:
- axe-core reports zero violations on the default render
- axe-core reports zero violations on key state variations (e.g., accordion open vs closed)
- Tests use semantic queries (
getByRole,getByText,getByLabelText) notgetByTestId - Mock data uses realistic hotel content
- All tests pass with
pnpm test - No TypeScript errors in the test file
- Pixel Perfect visual tests pass (
pnpm --filter storybook visual:test) — visual regression baselines must not be broken by any code change
Common Pitfalls
Section titled “Common Pitfalls”- Testing implementation details instead of behavior — Do not test internal state variables, CSS class names, or component structure. Test what the user sees and experiences: “heading is visible”, “clicking button shows content”, “image has alt text”.
- Not testing mapper edge cases — The Umbraco API can return null, undefined, empty strings, or missing fields for any optional property. The mapper must handle all of these without crashing. Test:
{ ...validData, optionalField: null },{ ...validData, optionalField: undefined }, and data with the optional field entirely absent. - Not testing all story variants as render cases — If Storybook has 6 story variants, there should be corresponding render tests for the key differences each variant represents.
- Brittle selectors — Avoid
container.querySelector('.m08-card-grid__item'). Usescreen.getByRole('heading', { name: 'Guest Rooms' })orscreen.getAllByRole('listitem'). - Forgetting async in interaction tests —
userEvent.click()and similar calls are async. Alwaysawaitthem. - Not cleaning up after tests — If a test modifies the DOM or uses timers, ensure proper cleanup.
@testing-library/reacthandlesrendercleanup automatically, but manual DOM manipulation needs explicit cleanup. - Missing accessibility test — Every component test file should include at least one axe-core integration test. This catches regressions early.
- Overly broad assertions —
expect(container).toBeTruthy()tests nothing useful. Assert specific content:expect(screen.getByRole('heading')).toHaveTextContent('Guest Rooms').
Example
Section titled “Example”Filled-in prompt for M08 Card Grid — Adding comprehensive tests:
Read the following context files first:- docs/dev-frontend-guides/03_MODULE_DEVELOPMENT_LIFECYCLE.md- packages/modules/src/m04-page-hero/m04-page-hero.test.tsx (use as test pattern reference)- packages/modules/vitest.config.ts- packages/modules/src/m08-card-grid/index.tsx- packages/modules/src/m08-card-grid/m08-card-grid.types.ts- packages/modules/src/m08-card-grid/m08-card-grid.mapper.ts- packages/modules/src/m08-card-grid/m08-card-grid.module.scss
Now add comprehensive tests to the following module:
**Module Path:** packages/modules/src/m08-card-grid/**Module Name:** Card Grid**Module ID:** M08**Test File:** packages/modules/src/m08-card-grid/CardGrid.test.tsx
**Current Test Coverage:** No test file exists.
**What to Test:**- Mapper: Yes- Component rendering: Yes- User interactions: No (Server Component, no interactivity)- Accessibility (axe-core): Yes
**Module Props:**- heading: string — Section heading- subheading?: string — Optional intro text- cards: CardItem[] — Array of card objects: - imageDesktop: ImageData - imageMobile: ImageData - title: string - description: string - link?: { url: string; label: string }- columns?: 2 | 3 | 4 — Desktop column count (default: 3)
**Specific Edge Cases to Cover:**- Empty cards array: cards = [] — should render heading but no cards- Missing optional link on cards: some cards have link, some do not- Missing subheading: component renders without subheading paragraph- columns defaults to 3 when not provided- Very long card title (100+ characters) — should not crash- Single card: cards array with only 1 item
**Mapper Input Shape (Umbraco API response):**{ "contentType": "cardGrid", "properties": { "heading": "Our Rooms & Suites", "subheading": "Discover luxury accommodation...", "columns": 3, "cards": [ { "imageDesktop": { "url": "/media/room-desktop.jpg", "width": 800, "height": 600, "alt": "Deluxe Suite" }, "imageMobile": { "url": "/media/room-mobile.jpg", "width": 400, "height": 300, "alt": "Deluxe Suite" }, "title": "Deluxe River Suite", "description": "Elegant suite overlooking the Thames with Art Deco furnishings.", "link": { "url": "/rooms/deluxe-river-suite", "label": "View Suite" } } ] }}
Create the test file at:packages/modules/src/m08-card-grid/CardGrid.test.tsx
Follow these conventions:- Use Vitest with @testing-library/react- Group tests with `describe` blocks: "Mapper", "Rendering", "Accessibility"- Test behavior, not implementation details- Mapper tests: valid input, missing subheading, empty cards array, null link, missing columns (default to 3)- Render tests: renders heading, renders correct number of cards, shows/hides subheading, shows/hides card links- A11y tests: axe-core on default render and on empty cards state- Use `screen.getByRole`, `screen.getByText` — avoid `getByTestId`- Mock data should use realistic hotel room and dining content- All tests must pass with `pnpm test`