Skip to main content
api-events uses Vitest for unit and integration tests, plus the repo-root e2e/ suite for full HTTP regression against Encore on :4000.

Test types

All commands run from api-events/.

Running tests

Unit tests

Integration tests

Requires ephemeral Postgres on :5434 (one-time setup):
Integration tests use DATABASE_URL=postgresql://postgres:postgres@localhost:5434/soundcheck_test?schema=public.

E2E regression

Requires Encore running on :4000 (or use the standalone runner):
Repo-root runner: ./api-events/scripts/run-encore-e2e.ps1 Set E2E_ENFORCE_COVERAGE=1 to fail when OpenAPI routes lack e2e hits (CI default in api-events-deploy.yml). Event-chat CRUD against tools/twilio-emulator is gated by E2E_EVENT_CHATS=1. The encore-e2e job sets that flag and adds event-chats to FEATURE_FLAG_OVERRIDES against the in-repo emulator (never a real Twilio account). tests/event-chats/routes-probe.test.ts still registers coverage when the suite is skipped locally. See e2e/README.md and the event chats runbook.

Writing unit tests

Mock Prisma and external clients at module boundaries:
See .agents/skills/api-events-testing/SKILL.md for project conventions (vi.mock paths, coverage expectations).

Writing integration tests

Integration tests live beside operations (*.integration.test.ts) and hit real Postgres:
Run only after test:integration:setup.

Coverage and CI gates

E2E coverage reads the OpenAPI snapshot (docs/openapi/soundcheck.json) and reports hits in e2e/coverage/endpoints.md.

Best practices

  • Unit — mock Prisma and outbound clients; test operations directly (no Encore boot).
  • Integration — isolate with ephemeral DB; clean fixtures per file.
  • E2E — exercise real HTTP on :4000; add a spec when adding routes.
  • Naming — colocate *.test.ts next to the module under test.

Troubleshooting

Run setup and confirm ephemeral DB:
Start infra + Encore:
Or use npm run test:e2e which orchestrates the stack.
Add an e2e hit for the new route or a justified waiver in e2e/src/coverage/waivers.ts. Exclusions in coverageExclusions.ts are retired — write coverage instead.