7.0 KiB
Testing Guide
Philosophy
- Test behaviour, not implementation: Focus on what the user can see and do, not internal details.
- Single source of truth per component: Each component should have one consolidated test file.
- Accessibility is mandatory: Basic a11y checks run as part of every component suite.
- E2E is sparse: Only cover critical user journeys that span pages or systems.
Test Structure
The test directory structure is organized as follows:
tests/
components/ # All component-focused tests (Vitest + RTL)
Button.test.tsx
Input.test.tsx
Checkbox.test.tsx
Select.test.tsx
Switch.test.tsx
pages/ # Page-level tests (home, blog, etc.)
home.test.jsx
blog.test.jsx
e2e/ # True end‑to‑end flows + visual regression (Playwright)
homepage.spec.ts
user-journeys.spec.ts
visual-regression.spec.ts
performance.spec.ts
utils/ # Shared test utilities
componentTestSuite.tsx
msw/ # MSW server setup for mocking
server.ts
accessibility/
e2e/ # E2E accessibility checks (WCAG compliance)
wcag-compliance.spec.ts
Component tests (tests/components/) use the standard componentTestSuite utility to ensure consistent baseline coverage for all UI components. Page tests (tests/pages/) cover page-level rendering and flows. E2E tests (tests/e2e/) focus on critical user journeys, visual regression, and performance. Accessibility E2E (tests/accessibility/e2e/) provides high-level WCAG compliance checks.
Standard Component Test Suite
Use the shared suite in tests/utils/componentTestSuite.tsx to get a consistent baseline:
import Component from "../../app/components/Component";
import {
componentTestSuite,
type ComponentTestSuiteConfig,
} from "../utils/componentTestSuite";
type Props = React.ComponentProps<typeof Component>;
const config: ComponentTestSuiteConfig<Props> = {
component: Component,
name: "Component",
props: {
/* default props */
} as Props,
requiredProps: ["label"],
optionalProps: {
disabled: true,
},
queries: {
getPrimaryElement: (s) => s.getByRole("button"),
},
variants: {
disabled: {
props: { disabled: true },
assert: (el) => {
expect(el).toBeDisabled();
},
},
error: {
props: { error: true } as Partial<Props>,
assert: (el) => {
expect(el).toHaveClass(
"border-[var(--color-border-default-utility-negative)]",
);
},
},
},
testCases: {
renders: true,
accessibility: true,
keyboardNavigation: true,
disabledState: true,
errorState: true,
},
};
componentTestSuite<Props>(config);
What the Standard Suite Covers
-
Rendering
- Component renders without throwing using the provided
props. - Required props are present and do not break rendering.
- Optional props can be applied without breaking.
- Component renders without throwing using the provided
-
Accessibility
- Runs
axeagainst the rendered output. - Fails on common WCAG 2.1 issues (roles, labels, contrast, etc.).
- Runs
-
Keyboard Navigation
- Ensures the primary element can receive focus.
- Smoke‑tests basic keyboard activation (
Enter,Space) without runtime errors.
-
Disabled State
- Uses
variants.disabledto verify disabled behaviour (e.g.,aria-disabled,disabledattribute, tab index).
- Uses
-
Error State
- Uses
variants.errorto verify error styling/attributes when applicable.
- Uses
When to Add Custom Tests
Use the standard suite for baseline coverage, then add custom describe blocks in the same file when:
- The component has important variants (different sizes, modes, label variants).
- There is non‑trivial interaction (menus, dropdowns, complex keyboard behaviour).
- You need to exercise stateful flows (forms, validation, error messages).
Example (inside the same *.test.tsx file):
describe("Input – behaviour specifics", () => {
it("calls onChange when user types", async () => {
// ...
});
});
Test Commands
-
All component tests (Vitest + RTL):
npm test -
Component-only tests (faster inner loop, focused on
tests/components/):npm run test:component # filter by name: npm run test:component -- --run tests/components/Button.test.tsx -
E2E tests only (Playwright):
npm run test:e2e # or, equivalently: npm run e2e
What to Test vs. What Not to Test
-
Do test
- Public behaviour: visible text, roles, labels, ARIA, keyboard paths.
- State transitions that users rely on (error -> success, disabled -> enabled).
- Critical component interactions (clicks, form submissions, dropdown selection).
- Accessibility invariants (no axe violations, basic keyboard support).
-
Avoid testing
- Pure styling details that are likely to change frequently (exact shadow radius, minor spacing).
- Internal implementation details (private helpers, hook internals, memoisation specifics).
- Responsive visibility in JSDOM (use Playwright visual / responsive tests instead).
Adding Tests for a New Component (≈5 minutes)
-
Create the component file in
app/components/. -
Create a test file in
tests/components/ComponentName.test.tsx. -
Wire the standard suite using
componentTestSuite. -
Add 1–3 custom tests for any unique behaviours.
-
Run:
npm run test:component -- --run tests/components/ComponentName.test.tsx
E2E and Visual Regression
-
Use Playwright for:
- Critical user journeys (e.g., create rule, navigate blog, key flows).
- Responsive behaviour and cross‑browser checks.
- Visual regression (
tests/e2e/visual-regression.spec.ts).
npm run test:e2e npm run visual:test
Storybook
Storybook is used for component documentation and visual review only. It is not used for automated testing.
- Component tests (
tests/components/*.test.tsx) provide all test coverage previously handled by Storybook test-runner - Storybook stories (
stories/*.stories.js) serve as living documentation and visual examples - Interaction functions are inlined in story files for demonstration purposes
- Run Storybook locally with
npm run storybookfor component development and review
Accessibility Testing
Accessibility is tested at two levels:
-
Component-level accessibility (
tests/components/*.test.tsx):- Automatically covered by
componentTestSuiteusingjest-axe - Tests roles, labels, ARIA attributes, keyboard navigation
- Runs as part of every component test suite
- Automatically covered by
-
Full-page accessibility (
tests/accessibility/e2e/wcag-compliance.spec.ts):- E2E tests using Playwright and
@axe-core/playwright - Validates WCAG 2.1 AA compliance across entire pages
- Tests complete user journeys for accessibility barriers
- E2E tests using Playwright and
This two-tier approach ensures both individual components and full page experiences meet accessibility standards.