__tests__/ folder beside the code it proves, anywhere in the repository (ADR 0022). There is no root tests/ folder and no shared tests workspace: each member owns its tests.
Where tests live
- A test file’s name is its subject’s name plus
.test(never.spec); its header says what the suite proves, and eachit()title is a full sentence stating behaviour. - The vitest presets set
passWithNoTests: false, so a member with an empty suite fails. Every layer or entry of a package ships at least one test. - Packages meet one coverage floor from
@stackra/vitest-config/coverage: lines and functions 80, branches 70. A threshold moves only upward; a package that cannot meet it says why in its ownvitest.config.ts. Apps are not gated. - Run one member with
pnpm turbo run test --filter=<package-name>; coverage withpnpm test:coverage.
Tests need zero secrets
No credential appears in a test, a fixture or a flow. A test that needs a real credential is a design finding, not a missing variable (Secrets).- Replace a provider (payments, mail, SMS, AI) with a recording fake at the seam where the code takes it as an argument or a port. The fake records calls so the test can assert on them (
assertSent,assertNothingSentTo) and can fail on demand (failNext("card_declined")). - A fake is the same shape as the real provider’s port and lives in the
testingentry of the package that owns the port, so every consumer reuses it. - Where a test must type a payment card, it uses the provider’s published test numbers only.
- Authenticated tests do not sign in: they build the same principal object the auth handler would produce and pass it to the endpoint.
Table-driven tests
When a surface publishes many similar cases (commands, routes, validation rules, locale rows), define the cases once as a typed table and drive oneit.each over it. The table is also the checklist: a new row without a case is visible in review. The same applies to the scaffold, which renders every template kind from one list in tools/scripts/scaffold.test.mjs.
What a green run proves
pnpm verify runs, in order: turbo run format:check lint typecheck test build, then pnpm validate (script tests plus the repository-shape validator), pnpm boundaries and pnpm knip. A green run proves formatting, lint and type-correctness for every member, that each member’s suite passes, that every build emits, and that the workspace contract holds (required files, tier tags, catalog versions, no unused code).
It does not prove three things:
It does not run a service or an app on a device
It does not run a service or an app on a device
Nothing in
verify starts a service, opens a browser, or launches a simulator. A wiring
mistake, a startup failure or a screen that only breaks on iOS is invisible to it. Say
“typechecks and unit-tests pass”, never “the service works”.It does not exercise the CI runner or reach the vault
It does not exercise the CI runner or reach the vault
The local gate runs on your machine, not in the runner image, and never touches the secret
vault. A job that needs a vault credential is reported as unexercised, not as passing; a stubbed
credential would prove nothing and risks a real value in a log. See CI.
It does not prove layout, direction or theme correctness
It does not prove layout, direction or theme correctness
Unit tests do not see pixels. Right-to-left layout, dark theme, dense text and screen-reader
behaviour are proved by the end-to-end matrix below and by the accessibility review (UI and
accessibility).
End-to-end matrix
An app’s e2e suite is a set of journeys run across axes, not a single configuration. Each project in the Playwright config is one combination:- The default run is a small, named subset (for example tablet light LTR, tablet dark LTR, tablet light RTL, phone light LTR). The full grid runs on a schedule or on demand.
- Journeys do not hard-code demo values or market literals: read them from the same source the app uses, and assert amounts by shape.
- A step that changes the screen may screenshot, named
<journey>-<step>-<viewport>-<locale>-<theme>; baselines are reviewed images, compared per combination. - Mobile journeys run against a simulator or device (Maestro or an equivalent); VoiceOver and split-screen checks stay manual and are listed in a checklist, not claimed as covered.
- Failures found by the suite in app code are reported to the app’s owner, with the failing step; a spec does not paper over them with workarounds without saying so.