Baseleg Docs
Reference · Architecture / Testing strategy · Baseleg Docs

Testing strategy

Baseleg uses a layered testing approach designed for a Cloudflare runtime and a modular monolith.

Unit + application tests (now)

  • Use Vitest for:
    • Domain rule tests (invariants, policies).
    • Application use case tests (happy paths + key failure paths).
  • Domain tests should not depend on Astro or D1 bindings.

Runtime-aware tests (now, for packages/infrastructure/repositories)

D1-bound flows and Workers bindings are tested with @cloudflare/vitest-pool-workers, which runs tests inside a real workerd runtime against a genuine (local, simulated) D1 database — not a hand-mocked DB object. This catches row↔entity mapping bugs (wrong column name, wrong nullability handling, a botched WHERE clause) that compile cleanly against a mock but fail against the real schema.

Version note: @cloudflare/vitest-pool-workers@0.13.0+ requires vitest@^4.1.0. This repo is on vitest@3.2.4, so it’s pinned to ^0.12.21 — the last minor compatible with 2.0.x - 3.2.x. Re-check compatibility before bumping either package.

Running locally:

pnpm -F @baseleg/infrastructure-repositories test

No wrangler login or Cloudflare account needed — the D1 binding is fully local/simulated.

How it’s wired (packages/infrastructure/repositories/):

  • vitest.config.tsdefineWorkersConfig with a DB D1 binding, compatibility date/flags mirroring apps/web/wrangler.jsonc, and this repo’s real db/migrations/*.sql loaded via readD1Migrations and passed in as a TEST_MIGRATIONS binding.
  • src/test/applyMigrations.ts (a setupFiles entry) — calls applyD1Migrations(env.DB, env.TEST_MIGRATIONS) before each test file runs, so tests run against the actual current schema, not a separately-maintained fixture that could drift from it. A broken migration file fails the whole test run loudly (a D1_ERROR from the SQL engine) — it does not silently skip or run against a partial schema.
  • src/test/env.d.ts — types the cloudflare:test module’s env.DB/env.TEST_MIGRATIONS.

CI: no separate job — .github/workflows/ci.yml’s existing Test step (pnpm test, which is turbo run test) already fans out to this package’s own test script, D1-bound tests included, since the pool is scoped to this one package only.

Pattern for adding a new D1-bound test for another *RepositoryD1 class: name the file <Name>.d1.test.ts (distinct from any mocked <Name>.test.ts in the same directory), import env from cloudflare:test, build a real DB via createDb(env.DB) — no manual binding setup needed, the harness above handles it. Seed any foreign-key parent rows directly via the Drizzle schema tables first: D1 enforces foreign keys, unlike default SQLite.

Backfilling D1-bound tests for the other existing *RepositoryD1/*D1 classes (AircraftRepositoryD1, BookingRepositoryD1, PersonRepositoryD1, OperatingHoursRepositoryD1, AircraftDispatcherD1, UsageEventRecorderD1) is real, separate follow-up work — only FlightRepositoryD1 has one today (a single smoke test proving the harness itself, not full coverage).

End-to-end journeys (later)

Use Playwright for critical user journeys (e.g. booking creation, conflict detection, grounded aircraft protection).

Regression requirement

Every bug fix requires a regression test:

  • Prefer adding a failing test first (where feasible).
  • Fix the bug.
  • Ensure the new test covers the regression scenario.