Curated, product-agnostic snapshot of the post-story-04 tree: demo content deleted, auth-only reference feature, web-next shell, all gates green. Product-specific docs, ADRs 027-029, PRDs/epics/archive, editor library traces, and product naming are curated out; generic template repairs (coverage provider devDeps, root test:coverage script, live lint fixes, root-only release-please) are kept. See TEMPLATE.md for provenance, curation list, and usage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
2.7 KiB
ADR-011: TDD Foundation
Status: Accepted Date: 2026-05-05 Supersedes: none
Context
The vertical-feature monorepo refactor (ADRs 001-010) established clean architecture with per-feature DI containers but did not enforce TDD as the path of least resistance. Agentic workers were producing code-first commits with tests added later, leading to test theatre and mock/real drift.
Decision
-
New package
@repo/core-testing(tag: tooling) — shared test utilities: defineFactory, defineContractSuite, renderWithProviders, mock-payload helpers, jsdom setup file. Taggedtoolingso any package may depend on it as devDependency without boundary violation. -
Vitest base configs split into node + jsdom with safety defaults (clearMocks, restoreMocks, mockReset, unstubGlobals, sequence.shuffle) and coverage thresholds (80/75/80/80 baseline; 100% in entities + use-cases + controllers).
-
Factories per feature in
src/__factories__/replace inline fixtures. Stable date defaults (2026-01-01) so snapshot diffs reflect SUT behavior only. -
Contract suites per repository interface in
src/__contracts__/run against every implementation (Mock + Payload). Eliminates the class of bug where the mock and the real impl drift apart. -
Tests in core-* packages and apps — composition smoke tests (appRouter, payloadConfig, bind-production, providers).
-
Storybook test-runner — every story executed as a smoke test.
-
CI workflow — typecheck + lint + boundaries + test + build + e2e + storybook on every PR. Coverage uploaded as artifact.
-
Two new docs — tdd-workflow.md (process) + restructured adding-a-feature.md (interleaves tests with impl).
Alternatives considered
- Fixture files instead of factories — rejected. Fixtures rot with schema changes and require manual updates per test.
- One shared test file per impl — rejected. Contract suites give the same coverage in fewer LOC and prevent drift.
- Real Postgres in tests via testcontainers — rejected for unit tests (slow, complex). Repository contract suites + vi.mock('payload') give equivalent confidence in milliseconds.
- Stryker mutation testing — deferred. Coverage thresholds + contract suites get us most of the way; mutation testing is incremental.
Consequences
- New package to maintain (small, mostly stable surface).
- Coverage thresholds may fail builds initially; we add tests to cross threshold as features land.
- Sequence shuffle may surface latent flakes; we fix as found.
- Templates for new features now require writing tests first; this is by design.
Refines
- ADR-006 (boundary tags) — adds @repo/core-testing as a tooling package.