The
test-storyskill must read this file before mapping acceptance criteria, running commands, or adding tests. Guidelines below match architecture.md: React 19.2, Vite 7.3.x, Vitest (latest), Tailwind CSS (latest), React Compiler, Node.js > 24.0.
- Unit / component tests: colocated
src/**/*.{test,spec}.{ts,tsx}(or a singletests/tree—stay consistent with the repo). - Integration / E2E: (add when introduced, e.g. Playwright under
e2e/—not required by the stack above). - Formal QA plans:
docs/test-plans/— fromcreate-testplan. Each plan must include a test-to-feature matrix (test case TC-* ↔ story feature ↔ AC). When executingtest-story, mirror that mapping in the story’s-test.mdreport so results stay test-to-feature aligned.
Run from the repository root with Node.js > 24.0 (match CI).
- Full suite:
npm testorpnpm testornpx vitest run(use whatever the project wires inpackage.json). - Watch mode:
npx vitest(ornpm run test -- --watchif scripted). - Single file:
npx vitest run path/to/File.test.tsx - Coverage (if enabled):
npx vitest run --coverage
- Prefer
vitest/configdefineConfigandmergeConfigwithvite.config.tsso aliases,define, React plugin, Tailwind pipeline, and React Compiler babel/plugin steps match production as closely as tests need. Ifvite.config.tsis a function, pass the sameconfigEnvinto both Vite andmergeConfig(see Vitest config: merge with Vite). - Set
test.environmenttojsdomorhappy-domfor React component tests; usenodefor pure utilities. - Use
setupFiles(e.g.src/test/setup.ts) for @testing-library/jest-dom matchers,cleanupif not using freshdocumentper test, and global test configuration. - Enable
globals: trueonly if the team wantsdescribe/it/expectwithout imports; otherwise import fromvitestexplicitly for clarity.
- Assert what users see and do: prefer Queries priority—
getByRole,getByLabelText, then text; avoidcontainer.querySelectorunless there is no accessible handle. - User events: use
@testing-library/user-event(async) over fire-and-forgetfireEventexcept for trivial cases. - Async UI: use
findBy*/waitForwith specific assertions; no fixedsetTimeoutsleeps. - Suspense / concurrent-ish flows: use RTL patterns that wait for final UI; avoid depending on intermediate render counts.
- Do not assert on number of renders,
useMemo/useCallbackidentity, or “memoization” behavior—the compiler changes how optimization happens. - Do assert on observable output: DOM, callbacks invoked, props-driven behavior, and error boundaries if applicable.
- If a test requires a non-compiled build, isolate it and document why; default path is same transform pipeline as dev/build.
- Do not assert on long Tailwind class strings on DOM nodes unless the AC explicitly requires a token or variant (brittle and couples tests to markup).
- Prefer roles, names, and visible text; for visual regression, use a dedicated tool (e.g. Chromatic) if the team adopts it—not
toHaveClassspam. - When testing conditional styling, assert behavior (e.g. disabled button cannot be clicked) or state exposed via
aria-*, not the exact utility classes.
- Use
vi.mock()for modules;vi.spyOnfor individual exports. Reset between tests withvi.clearAllMocks/ project defaults (clearMocks,restoreMocksin Vitest config). - Timers:
vi.useFakeTimers()only when needed; alwaysvi.useRealTimers()inafterEachif enabled. - Network: prefer
MSWfor fetch-level integration in Node/jsdom when tests need stable HTTP; avoid real network I/O in unit tests.
- File naming:
*.test.ts/*.test.tsxnext to source, or*.spec.tsx—one convention per repo. - Describe blocks: name by behavior or component + scenario, not implementation details.
- Coverage: if enforced, exclude
*.config.*, generated files, and pure re-exports; don’t chase 100% at the cost of meaningful assertions.
- One clear user-observable outcome per test when testing UI.
- Avoid flaky patterns: real network,
Date.now()without mocking, unordered list assertions without sorting. - Align names and structure with story acceptance criteria so
docs/stories/<slug>-test.mdcan cite test file + case directly.
- Do not lower TypeScript strictness or ESLint rules only to green tests.
- Do not delete tests without replacing behavior coverage or an explicit product decision to drop that behavior.
- Do not run tests on Node < 24 if the architecture requires Node > 24—fix the environment instead.