Skip to content

Testing and Validation

Emmanuel Knafo edited this page Jun 18, 2026 · 1 revision

Testing and Validation

Validation is part of the Spec-Driven Development loop, not a separate phase bolted on at the end. The constitution requires that every change keep the build deterministic and accessible, so the checks that prove those properties run as ordinary npm scripts.

The validation commands

npm run type-check   # TypeScript, no emit
npm run lint         # ESLint flat config (eslint .)
npm run build        # next build -> static export to out/
npm run test:e2e     # responsive navigation + content contract
npm run test:a11y    # axe accessibility scan of all four pages
Command What it guarantees
type-check Types are sound across the app and content modules
lint Code style and Next.js best practices hold
build The site exports cleanly to static HTML in out/
test:e2e Navigation works at every viewport and the content invariants hold
test:a11y No detectable accessibility violations on any page

How the suites map to the spec

Each Playwright suite traces back to requirements and success criteria in the specification.

flowchart LR
    SPEC[spec.md\nrequirements + success criteria] --> CC[content-contract.spec.ts]
    SPEC --> A11Y[primary-pages.spec.ts]
    SPEC --> RN[responsive-navigation.spec.ts]
    CC --> OUT[Validated static site]
    A11Y --> OUT
    RN --> OUT
Loading

Content contract (tests/build/content-contract.spec.ts)

Asserts the data invariants directly against the typed content modules, with no browser involved:

  • exactly 20 episodes
  • exactly one featured episode, and it is within the catalog
  • sequential episode numbers 1 through 20
  • unique ids, slugs, and titles
  • every episode carries mock-action metadata
  • at least six FAQ items
  • the show is named Signal & Static

These map to FR-004, FR-005, FR-008, FR-016, FR-017, and the matching success criteria.

Accessibility (tests/accessibility/primary-pages.spec.ts)

Runs an axe scan against /, /episodes, /about, and /faq using the wcag2a, wcag2aa, wcag21a, and wcag21aa rule sets, and verifies the featured episode is exposed as an accessible region with the expected headings. Maps to FR-012, FR-013, and SC-006.

Responsive navigation (tests/e2e/responsive-navigation.spec.ts)

Exercises three viewports — mobile 390x844, tablet 768x1024, and desktop 1440x900 — checking for no horizontal overflow, that navigation reaches every page, that the landing page features exactly one episode with a mock action, and that the episodes page lists exactly twenty items. Maps to FR-009, FR-011, and SC-002, SC-003, SC-005.

Testing the real artifact, not the dev server

The Playwright suites run against the exported static build, not the Next.js development server. A small zero-dependency static server (scripts/serve-out.mjs) serves the out/ directory, and playwright.config.ts runs npm run build && npm run serve:static before the tests.

Why this matters: the dev server compiles routes on demand, which delays client-side navigation and produces flaky timing in tests. Serving the real static output removes that discrepancy and means the tests exercise exactly what ships to production. This aligns with the constitution's Static Output First and Fast, Stable Delivery principles.

Current status

All checks pass:

  • type-check, lint, and build are clean; the build exports five routes (/, /episodes, /about, /faq, plus 404) to out/.
  • test:e2e17 passing (content contract + responsive navigation).
  • test:a11y7 passing (axe scans and heading checks).

A separate review confirmed there are no secrets, tokens, fetch calls, or external feed dependencies in the client code — the only http:// references are the SVG XML namespace and local development URLs.

For the architecture these tests protect, see Architecture.

Clone this wiki locally