Skip to content

Testing

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.

WorkspaceCommandWhat it checks
@quiz-builder/uipnpm --filter @quiz-builder/ui testAll shadcn primitives smoke-test
@quiz-builder/apipnpm --filter @quiz-builder/api testSmoke routes, auth sign-up, /api/me, quiz API integration
@quiz-builder/webpnpm --filter @quiz-builder/web testApp shell renders
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 scoring

API 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:

Terminal window
pnpm test
Terminal window
pnpm typecheck

apps/docs uses astro check instead of tsgo.

Visual, a11y, and interaction review for shared UI and web feature components:

Terminal window
pnpm dev:storybook
pnpm --filter @quiz-builder/storybook build
pnpm test:storybook

pnpm 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)
Story prefixShellTheme
UI/*None (component only)@storybook/addon-themes class toggle
Web/*AppProviders + TanStack Router memory historynext-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.

  • Orval API routes — use handlers from @quiz-builder/api-client/msw as an array: parameters: { msw: { handlers: [getListQuizzesMockHandler(...)] } }

Helper: mswHandlers(...handlers) in apps/storybook/.storybook/msw-helpers.ts returns the correct parameters shape.

StoryWhat it covers
Web/DashboardSessionSession panel via GET /api/me
Web/QuizListList, empty state, create-quiz navigation
Web/QuizEditorDraft editing and validation
Web/QuizPublishedPublished read-only view and copy link toast
Web/LoginForm / Web/RegisterFormAuth forms — states + interaction tests (play)
Web/QuizTakeTake form, validation, score panel, submit MSW
Web/TakeQuizPageFull 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.

Component typeWhere to testData source
Presentational UIpackages/ui or apps/web Vitest (jsdom)Props or Orval Faker
Interactive / data hooksStorybook play() + MSW@quiz-builder/api-client/msw
API behaviorapps/api workers testsReal D1
Full journeysPlaywright e2eReal servers

apps/e2e hosts Playwright tests against real Vite (:4173) and Wrangler (:8787) dev servers. The API web server applies local D1 migrations before starting.

SpecCoverage
smoke.spec.tsWeb home, API /health, OpenAPI /doc
auth.spec.tsRegister form rejects duplicate email
quiz-journey.spec.tsRegister → create quiz → publish → anonymous take + score
quiz-published.spec.tsPublished quiz is read-only for the author
not-found.spec.tsInvalid permalink and missing owned quiz

Root scripts:

Terminal window
pnpm test:e2e
pnpm test:e2e:ui

pnpm test:e2e:ui opens the Playwright UI for picking tests, watching runs, and debugging.

Lefthook runs format:check, lint:check, and typecheck on pre-push. Pre-commit formats and lints staged files.