Repository navigation
Code Web Tests
tests/ sits beside src/ so the source tree contains source and nothing else.
The split is by cost, which is what makes it useful — you can run the cheap
ones on every save and the expensive ones on demand.
| Directory | What belongs here | Cost |
|---|---|---|
units/ |
Fast, deterministic, no build and no browser. Stub the boundary. | ~ms |
integration/ |
Several real layers at once — a real Vite build, or Testing Library + MSW + the real API client + TanStack Query + i18next. | ~100s of ms |
e2e/ |
Playwright, against a real production build. | seconds |
support/ |
Harness, not tests. MSW server and handlers, fixtures, the ajv contract validator, the OpenAPI reader. | — |
pnpm test # units + integration
pnpm test:unit # just units
pnpm test:integration # just integration
pnpm e2e # Playwrighte2e/ is excluded from Vitest explicitly. Vitest's default include matches
*.spec.ts, and picking up Playwright specs fails with a confusing "two
different versions of @playwright/test".
Outside CI the suite runs with three workers and a 15-second test limit
(vite.config.ts). CI keeps vitest's defaults, so a test that is too slow still
fails there. Pass --maxWorkers=<n> to use more workers on an idle machine.
Ask what it would take to make it fail for a reason unrelated to the thing it tests. If the answer is "a slow disk" or "a flaky browser", it is not a unit test.
- Stubs
fetch, reads a file, parses the contract → units - Renders a component that fetches → integration
- Drives a browser → e2e
@/… is src/, @tests/… is tests/. Tests import production code through
@/ like anything else; there are no deep relative paths between the two trees.
support/contractResponse.ts validates every MSW fixture against
api/openapi.yaml with ajv before returning it. A hand-written mock is a
second, unversioned implementation of the API: without this, someone adds a
field to the contract, the handler keeps returning the old shape, and component
tests stay green about a payload production will never send. A drifted mock
fails at the mock rather than inside whatever it was meant to be testing.
units/contract/ asserts structural invariants of the contract itself —
the §13.5 student-payload boundary, the §6.5 public-endpoint rules, pagination,
operationId uniqueness. Its helpers are unit-tested against synthetic
documents, because a checker nobody checks is decoration.
units/styles/tailwind-classes.test.ts reads every colour utility (bg-,
text-, border- and its side forms, ring-, shadow- and the rest) in src/
and fails when one names no --color-* or --shadow-* key of index.css's
@theme, no Tailwind default and no non-colour utility. Tailwind generates no
CSS for such a class, and a test that only asserts the class name passes anyway;
bg-accent-soft shipped that way.
The scan is a token regex over each file's text with its comments removed, not a
parse, so it sees a class the same way inside a template literal, cn(...),
cva(...) and clsx(...), and it cannot tell a class from a string that looks
like one. Variants, the /50 opacity suffix and the ! marker are stripped
first. A value in brackets or parentheses (text-[13px], bg-(--x)) is
arbitrary and skipped. The longest prefix wins, so border-t-brand is read as
side border-t with colour brand, not as border with t-brand. A new
non-colour suffix (say border-spacing-*) goes in the test's NON_COLOUR table,
and a CSS word that merely starts with a prefix (border-box) in CSS_WORDS.
Generated from web/tests/README.md. Edit that file in the repository; changes made on this page are overwritten.
Generated from the repository's documentation on every push to develop.
Start here
Product
Implementation plan
- 00 Architecture overview
- 10 Phase 0: Scaffold and contract
- 11 Phase 1: Auth, join, shells
- 12 Phase 2: Admin authoring
- 13 Phase 3: Assign and take
- 14 Phase 4: Grade and results
- 15 Phase 5: Hardening
- 16 Phase 4.5: The student at a desk
- 17 Word import: milestone plan
- 18 Word import: teacher workflow
- 19 Versioned content contract
- 20 Data model
- 30 Risk register
- 40 Open items
- 50 Non-functional requirements
- 60 Backend architecture
- 91 September 2026 issue remediation
- 92 Student layouts and interaction rules
Redesign (Phase R)
- 70 Redesign overview
- 71 R1: Foundations (v0.7.0)
- 72 R2: Access (v0.8.0)
- 73 R3: Student console (v0.9.0)
- 74 R4: Teacher workspace (v0.10.0)
- 74d D4: Deck update (v0.11.0)
- 74e E1: Moving a question across a group
- 75 R5: Admin console and email (v0.12.0)
- 76 R6: Question types and scoring (v0.13.0)
- 77 R7: Collaboration (v0.14.0)
- 78 R8: Schedule (v0.15.0)
- 79 R9: Insights (v0.16.0)
- 80 R10: Learn (v0.17.0)
- 81 R11: Landing, leads, v1.0 (v1.0.0)
Setup and operations
- CI
- Deploying
- DNS for quizzivy.com
- Google OAuth client
- Production operations
- Cloudflare R2 bucket
- Word import worker
- R4 rehearsal on a Neon branch
Design
Team
- Agent team
- Verification environment
- Team ledger
- R4 readiness
- R4 verification strategy
- T-R4.51 browser verification
Code READMEs