Testing
The stack
- Vitest + React Testing Library for unit and integration tests. Files:
src/**/*.test.ts(x). Setup insrc/test/setup.ts(mocks for next-intl, next/navigation, Sentry). - Playwright (Chromium) for end-to-end tests. Files:
e2e/**/*.spec.ts. It starts the dev server automatically when run locally.
pnpm test # watch mode
pnpm test:run # run once
pnpm test:coverage # with coverage
pnpm test:e2e # Playwright E2E
What each layer tests
Test type follows the layer being changed:
| Layer | Test type |
|---|---|
src/lib/** | Vitest unit tests |
src/server/routers/** | Vitest integration (mocked Prisma + auth context) |
src/components/** | React Testing Library |
| User-visible flows | Playwright E2E |
Definition of done
Testing in this kit is a development requirement, not an afterthought:
- Every new feature ships with its tests in the same change. A feature with failing, skipped, or missing tests is an open task, not a finished one.
pnpm test:runandpnpm lintgreen are part of the deliverable.- Bug fixes add a regression test that fails before the fix and passes after.
- Behavior changes update the affected tests. If you change what code does and every test still passes untouched, that's a red flag — the suite is tolerating the change through passive mocks instead of asserting it.
- Never weaken a test to make it pass — no deleting assertions, loosening
matchers, or adding
.skip. If a test no longer reflects intended behavior, rewrite it for the new intent in the same change.
Writing tests against org-scoped routers
Integration tests mock Prisma and the auth context, then assert both the happy
path and the isolation guarantees — e.g. that a query filters by
organizationId and that the wrong tier is rejected. The existing router tests
in src/server/routers/*.test.ts are the pattern to copy.
Parity test
messages-parity.test.ts asserts that en.json and es.json have identical
keys. Add a translation to only one file and the suite goes red — a cheap guard
against half-translated UI (see Internationalization).