Testing
Philosophy (scaffold phase)
Section titled “Philosophy (scaffold phase)”Tests prove each workspace builds, typechecks, and runs. API integration tests use @cloudflare/vitest-pool-workers with an in-memory D1 database and applied migrations. Feature UI with data fetching is covered in Storybook using Orval-generated MSW handlers.
Unit and integration tests
Section titled “Unit and integration tests”| Workspace | Command | What it checks |
|---|---|---|
@quiz-builder/ui | pnpm --filter @quiz-builder/ui test | All shadcn primitives smoke-test |
@quiz-builder/api | pnpm --filter @quiz-builder/api test | Smoke routes, auth sign-up, /api/me, quiz API integration |
@quiz-builder/web | pnpm --filter @quiz-builder/web test | App shell renders |
API test layout
Section titled “API test layout”apps/api/test/ setup/ apply-migrations.ts # applies D1 migrations before tests env.d.ts # TEST_MIGRATIONS binding types helpers/ auth-request.ts # shared Better Auth request helper smoke/ routes.test.ts # /health, /doc, CORS, /api/auth/ok integration/ auth.test.ts # sign-up + unique email constraint me.test.ts # GET /api/me session responses quizzes.test.ts # creator CRUD, publish immutability, public scoringAPI tests run inside the Workers runtime via @cloudflare/vitest-pool-workers, with auth secrets and D1 bindings provided through vitest.config.ts. Application code uses Zod v4; the test runner keeps an isolated Zod v3 resolution via pnpm-workspace.yaml until @cloudflare/vitest-pool-workers fully supports v4 under the monorepo override.
Run all package tests from the repo root:
pnpm testType checking
Section titled “Type checking”pnpm typecheckapps/docs uses astro check instead of tsgo.
Storybook
Section titled “Storybook”Visual, a11y, and interaction review for shared UI and web feature components:
pnpm dev:storybookpnpm --filter @quiz-builder/storybook buildpnpm test:storybookpnpm test:storybook runs Storybook interaction tests (play() functions) in a headless Chromium browser via Vitest.
Storybook loads:
packages/ui/src/**/*.stories.tsx— shadcn primitives (UI/*titles)apps/web/src/**/*.stories.tsx— feature UI with TanStack Query + MSW (Web/*titles)
Decorators
Section titled “Decorators”| Story prefix | Shell | Theme |
|---|---|---|
UI/* | None (component only) | @storybook/addon-themes class toggle |
Web/* | AppProviders + TanStack Router memory history | next-themes via AppProviders |
Web stories can set parameters.router.initialEntries (for example ["/login"] or ["/q/aB3xY9"]) so page stories mount on the correct route. Non-focused routes render lightweight stubs so navigation assertions work after mutations.
MSW conventions
Section titled “MSW conventions”- Orval API routes — use handlers from
@quiz-builder/api-client/mswas an array:parameters: { msw: { handlers: [getListQuizzesMockHandler(...)] } }
Helper: mswHandlers(...handlers) in apps/storybook/.storybook/msw-helpers.ts returns the correct parameters shape.
Web story inventory
Section titled “Web story inventory”| Story | What it covers |
|---|---|
Web/DashboardSession | Session panel via GET /api/me |
Web/QuizList | List, empty state, create-quiz navigation |
Web/QuizEditor | Draft editing and validation |
Web/QuizPublished | Published read-only view and copy link toast |
Web/LoginForm / Web/RegisterForm | Auth forms — states + interaction tests (play) |
Web/QuizTake | Take form, validation, score panel, submit MSW |
Web/TakeQuizPage | Full public take page with load + submit |
Web stories use msw-storybook-addon with handlers from @quiz-builder/api-client/msw (generated by Orval) where routes are in the OpenAPI spec. Example: Web/DashboardSession mocks GET /api/me.
Testing split
Section titled “Testing split”| Component type | Where to test | Data source |
|---|---|---|
| Presentational UI | packages/ui or apps/web Vitest (jsdom) | Props or Orval Faker |
| Interactive / data hooks | Storybook play() + MSW | @quiz-builder/api-client/msw |
| API behavior | apps/api workers tests | Real D1 |
| Full journeys | Playwright e2e | Real servers |
End-to-end
Section titled “End-to-end”apps/e2e hosts Playwright tests against real Vite (:4173) and Wrangler (:8787) dev servers. The API web server applies local D1 migrations before starting.
| Spec | Coverage |
|---|---|
smoke.spec.ts | Web home, API /health, OpenAPI /doc |
auth.spec.ts | Register form rejects duplicate email |
quiz-journey.spec.ts | Register → create quiz → publish → anonymous take + score |
quiz-published.spec.ts | Published quiz is read-only for the author |
not-found.spec.ts | Invalid permalink and missing owned quiz |
Root scripts:
pnpm test:e2epnpm test:e2e:uipnpm test:e2e:ui opens the Playwright UI for picking tests, watching runs, and debugging.
Local pre-push checks
Section titled “Local pre-push checks”Lefthook runs format:check, lint:check, and typecheck on pre-push. Pre-commit formats and lints staged files.