Testing & Quality
Testing isn't optional — it's how you prove you care.
Quality here isn't a checklist. It's a design force — every layer of the stack has a gate, every gate has teeth, and nothing reaches production without proving it belongs there.
Test-Driven Design
- TDD — tests drive design, not just verify it
- No mocking frameworks —
FakeHttpClient, hand-written fakes, deterministic tests - Mutation testing (Stryker) — test quality score >= 0.95
- 100% code coverage as design pressure, not a vanity metric
- Property-based testing (fast-check) for fuzzy invariants
Code Quality as Static Analysis
Not opinions — metrics. QualityGate runs Roslyn-powered analysis on every build: cyclomatic complexity, cognitive complexity, afferent/efferent coupling (Ca/Ce), cohesion (LCOM4), maintainability index. Thresholds live in quality-gate.yml, enforced in CI with pass/fail exit codes. The build doesn't warn — it fails.
Visual Quality as Baselines
Every page is screenshotted across 4 themes (dark, light, dark-hc, light-hc) and multiple viewports. Baselines are checked in. When a pixel changes, the diff is visible and intentional — or the test fails.
New pages get auto-generated baselines on first run. A smoke mode tests a curated set of stable pages on every push, so content additions don't break the suite. Full regression runs on demand.
Accessibility as a Gate, Not an Afterthought
axe audits on every page, accent color contrast matrix testing, ARIA role verification, keyboard-first navigation, screen-reader announcements. Accessibility isn't a separate pass — it's woven into the same test pipeline that checks rendering.
Requirements as Compile-Time Proof
Features are abstract classes with acceptance criteria as abstract methods. Tests link to features via typed decorators. A compliance scanner verifies 100% AC coverage — if an acceptance criterion has no test, the build knows.
The Gate Before Push
Husky pre-push hook: unit tests + smoke Playwright + compliance scan. All three must pass before git push succeeds. No bypassing, no --no-verify. If the gate fails, the code stays local until it's fixed.