Add an integration test
Add a test that exercises real wiring between components — the seams a unit test mocks away — matching the repo's existing integration setup, not a new harness.
Steps
- Read the lore first. Call
search_lore(Memory MCP) for the repo's integration-test conventions: how the test DB/containers are provisioned, fixtures, and where these tests live (they're often separated from unit tests). - Find an existing integration test and copy its bootstrap — the test client, DB setup/teardown, seeding, and how external services are stubbed at the boundary. Use real collaborators internally; stub only true externals (third-party APIs).
- Enumerate the flow from the ticket/AC: the entry point, the path through the components, and the observable outcome (HTTP status + body, persisted row, emitted event). Cover the happy path plus at least one failure path.
- Write the test in the repo's integration location and convention, with proper setup/teardown so it's isolated and repeatable. Assert on real outcomes, not internals.
- Run it with the repo's integration command (see the context packet; it may differ
from the unit
testscript). Iterate until green and stable. - Evidence: the command + passing summary and the new test paths. Then use the
record-evidenceskill to recordtest_outputagainst the AC and submit for review.
SQLite isolation (this repo)
The packages/memory suite talks to a real SQLite DB (better-sqlite3). Copy its
isolation conventions rather than inventing new ones:
- Fresh DB per test, in-memory. A
newDb()helper builds each one from scratch —new BetterSqlite3(":memory:"), thendb.pragma("foreign_keys = ON"), thenrunMigrations(db)— so every test starts on the current schema with no leaked rows. Prefer this over sharing one DB across a file. - When you need a real on-disk DB (path handling, WAL,
openDb()), create it under a temp dir inbeforeEach—mkdtempSync(join(tmpdir(), "memory-<area>-"))— and tear it down inafterEachwithrmSync(dir, { recursive: true, force: true }).openDb(path)already applies migrations and pragmas, so use it instead of hand-rolling setup. - Keep
foreign_keys = ONso the test exercises the same referential constraints production does; a test that silently drops them can pass on data the app would reject. - One DB lifecycle per test (
beforeEach/afterEach), never a module-level singleton — that's what keeps runs order-independent and repeatable.
Rules
- Test real wiring; mock only genuine externals, not the components under test.
- Ensure isolation — no leaked state between runs, deterministic setup/teardown.
- Match the repo's integration harness; don't install or stand up a new one.
- Run on a branch (the
create-branchskill), never a protected branch.