RFC: Testing Conventions Standardization
- Status: Draft
- Authors: GitHub Copilot
- Reviewers: TBC
- Created: 2025-10-12
- Target Release: Q4 2025 test suite refresh
1. Background & Motivation
The server-side test suite under worker/__tests__ has grown organically. Each suite wires services, factories, and context objects differently, which leads to:
- duplicated setup code with subtle differences
- inconsistent typing, including
anycasts and untyped factories - higher maintenance cost when services change
- unclear expectations for new contributors
We want to standardize the test harness around a simple, predictable set of helpers that embrace the project's emphasis on KISS (Keep It Simple, Stupid) and strong TypeScript typing.
2. Goals
- Provide a single entry point for service and router instantiation in tests
- Eliminate
anycasts by codifying shared test context types - Reduce per-suite boilerplate via reusable, typed data builders
- Encourage deterministic, isolated tests with consistent setup/teardown patterns
- Document expectations for future test additions or refactors
3. Non-Goals
- Rewriting production service factories or runtime dependency injection
- Migrating frontend test suites (none today)
- Introducing heavyweight frameworks or abstractions beyond Vitest
4. Proposed Conventions
4.1 Service Bootstrapping
- Refactor
worker/services/factory.tsso production and test runners share a singlebuildCoreServices({ db, env, overrides })implementation. Tests pass a lightweightenvstub and optional overrides (e.g., fake OAuth secrets); production relies on real values. - Collapse duplicated test wiring by replacing
worker/__tests__/factories/database.ts#createDomainServiceswith calls into the shared builder. Expose a thincreateTestServices()wrapper that handles test-specific extras (currently market data + fund snapshots) while delegating core instantiation to the shared factory. - Provide typed helpers to access individual services (e.g.,
getAuthService(services)returnsAuthService). - All service suite tests import the shared factory instead of constructing repositories manually.
4.2 tRPC Context Helpers
- Define
TestCallerContextandTestUserContexttypes inworker/__tests__/utils/test-helpers.ts. - Add
createTestCaller(services, userOverrides?)that returns a fully typedappRouter.createCallerinstance. - Middleware and router tests rely on this helper, overriding user roles or org IDs via parameters.
4.3 Data Builders & Scenarios
- Keep existing simple entity factories; ensure each exports a typed
createXFactory(overrides?: Partial<XProps>)with sensible defaults. - For recurring multi-entity setups (e.g., fund + investor), consolidate into scenario builders under
worker/__tests__/factories/scenarios/with explicit return types. - Document expected defaults in factory files to prevent hidden magic numbers.
- Keep fixtures deterministic with hard-coded values; avoid introducing faker libraries for now.
4.4 Fixture Lifecycle
- Standardize on Vitest
beforeAll/afterEachfor resetting service instances and globals. - Cloudflare Workers Vitest integration provisions isolated storage per test run, so no manual D1 reset is required unless future regressions surface.
- Prefer stateless utilities and plain objects over classes for fixtures.
4.5 Assertion Utilities
- Provide minimal helpers in
worker/__tests__/utils/assertions.tsfor common patterns (e.g.,expectMinorUnitsEqual(a, b)). - Keep helpers pure functions to preserve flexibility; avoid extending
expectunless essential. - Add basis points documentation inline when relevant, per project conventions.
4.6 File & Naming Conventions
- Shared utilities live in
worker/__tests__/utils/. - Factories remain under
worker/__tests__/factories/with suffix.factory.ts. - Scenario builders use
.scenario.tsnaming. - New tests include a short header comment describing the suite's focus only when clarity is needed.
5. Rollout Plan
- Audit: Catalogue current suite setups, identifying deviations and bespoke helpers.
- Implement Core Utilities: Extract shared service factory + helpers, remove duplicate test factory wiring, and update README with usage examples.
- Refactor by Category:
- Services
- Domain
- Coordinators
- tRPC / middleware
- Regression Checks: After each category, run
pnpm typecheckandpnpm test. - Documentation: Finalize README updates and migrate TODO items tracking.
6. Risks & Mitigations
- Risk: Hidden coupling uncovered during refactor
- Mitigation: Refactor incrementally, commit per category, rely on full test runs.
- Risk: Shared helpers grow complex over time
- Mitigation: Enforce KISS by reviewing helper APIs during PRs; avoid over-parameterization.
7. Open Questions
- None for now; snapshot tests and faker libraries remain out of scope.
8. Implementation TODOs
- Validate Cloudflare Workers Vitest isolation with a smoke test that mutates D1 state across suites and confirm it resets between tests.
- Extract
buildCoreServices(shared factory) insideworker/services/factory.ts; ensure production paths rely on it. - Create
createTestServiceswrapper inworker/__tests__/factories/test-services.tsdelegating tobuildCoreServicesand stitching in test-only services (market data, fund snapshots). - Update existing test factories and suites to import the new helpers instead of bespoke instantiation.
- Introduce shared type exports (
TestServices,TestCallerContext, etc.) inworker/__tests__/utils/test-helpers.tsalongside acreateTestCallerhelper. - Consolidate scenario builders with explicit, hard-coded fixtures; remove any dynamic or random data generation.
- Revise
worker/__tests__/README.mdwith conventions, examples, and checklist for new tests. - Refactor test suites category-by-category, running
pnpm typecheckandpnpm testafter each tranche.
9. Next Steps
- Collect feedback and answer open questions.
- Upon approval, implement core helpers and update the README.
- Schedule category-by-category refactor tasks.