Testing strategy
Testing protects, in order: tenant isolation, data integrity, the contract, the experience (TEST_STRATEGY).
| Layer | Tooling | Shape today |
|---|---|---|
| Unit (web/domain/mobile) | Vitest / Jest | ~250 tests: pure helpers, components over a stubbed transport |
| Integration (api/db/worker) | Vitest + real Postgres | ~215 tests incl. the negative-auth registry and fault-injection atomicity |
| End-to-end | Playwright against a built app | 35 journeys incl. axe scans on every major surface |
| Visual/primitives | Storybook (+a11y addon) | Primitives and pattern stories |
House rules that bite:
- E2E serves the last build — rebuild before running after web changes.
- Contract-changing PRs run
turbo run test --force(cache-masking incident). - Axe assertions wait for toasts to detach and entry animations to finish — both produce false contrast failures mid-transition.
- Keyboard journeys are asserted with real focus, not simulated class checks.
Repository gates that are easy to trip
Section titled “Repository gates that are easy to trip”Two checks run inside pnpm lint and fail the build rather than warning:
- Research-id uniqueness.
docs/product/RESEARCH_BACKLOG.mdis the canonical register of deferred scope, and everyR-NNis referenced from PR descriptions and the execution plan. If you add an entry, give it a new id — defining an existing one twice forks the register, and the check will tell you which id and which lines. When renumbering, update references by meaning:R-5is a substring ofPR-5, so a global search-and-replace will corrupt history. Run the gate’s own fixture tests withpnpm check:research-ids. - Design-token contrast. The twelve Badge tone pairs are measured against WCAG AA in
packages/design-tokens. If you change a colour token, that test tells you whether the pair still clears 4.5:1. Choosing the colour is a design decision; clearing AA is arithmetic.