Skip to main content

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 any casts 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 any casts 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.ts so production and test runners share a single buildCoreServices({ db, env, overrides }) implementation. Tests pass a lightweight env stub and optional overrides (e.g., fake OAuth secrets); production relies on real values.
  • Collapse duplicated test wiring by replacing worker/__tests__/factories/database.ts#createDomainServices with calls into the shared builder. Expose a thin createTestServices() 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) returns AuthService).
  • All service suite tests import the shared factory instead of constructing repositories manually.

4.2 tRPC Context Helpers

  • Define TestCallerContext and TestUserContext types in worker/__tests__/utils/test-helpers.ts.
  • Add createTestCaller(services, userOverrides?) that returns a fully typed appRouter.createCaller instance.
  • 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/afterEach for 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.ts for common patterns (e.g., expectMinorUnitsEqual(a, b)).
  • Keep helpers pure functions to preserve flexibility; avoid extending expect unless 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.ts naming.
  • New tests include a short header comment describing the suite's focus only when clarity is needed.

5. Rollout Plan

  1. Audit: Catalogue current suite setups, identifying deviations and bespoke helpers.
  2. Implement Core Utilities: Extract shared service factory + helpers, remove duplicate test factory wiring, and update README with usage examples.
  3. Refactor by Category:
    • Services
    • Domain
    • Coordinators
    • tRPC / middleware
  4. Regression Checks: After each category, run pnpm typecheck and pnpm test.
  5. 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) inside worker/services/factory.ts; ensure production paths rely on it.
  • Create createTestServices wrapper in worker/__tests__/factories/test-services.ts delegating to buildCoreServices and 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.) in worker/__tests__/utils/test-helpers.ts alongside a createTestCaller helper.
  • Consolidate scenario builders with explicit, hard-coded fixtures; remove any dynamic or random data generation.
  • Revise worker/__tests__/README.md with conventions, examples, and checklist for new tests.
  • Refactor test suites category-by-category, running pnpm typecheck and pnpm test after 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.