test(integration): say so when the database loses its schema (#154)
Linting / lint (pull_request) Successful in 2m20s
SonarQube Analysis / sonarqube (pull_request) Successful in 26m0s

When the integration run lost its schema partway through, it presented as 36 assertion errors about categories, price filters and favourite notifications. The real message — `relation "items" does not exist` — was further down the same log, and hours went into chasing the assertions instead.

The cause is still open and needs runner-side evidence this cannot reach: whether the Postgres service container is being recreated mid-run, which would come back with an empty data directory. This is the half that can be fixed from here — whatever the cause, the next occurrence reads as "the database lost its schema" on the first line, names which tables are gone, and says that nothing in the suite drops tables so the database was replaced underneath the run.

globalSetup asserts once after migrating, which establishes the fact the rest of the run depends on. Without it, a run that never had a schema and one that lost it midway are indistinguishable from the failures they produce.

resetDb checks only when its TRUNCATE fails, rather than on every reset. It runs in a beforeEach several hundred times a suite, and an extra round trip each time to guard against a rare event would be paying continuously for it. When the schema is fine, an unrelated failure is passed through untouched rather than dressed up as a schema problem.

The diagnostic is tested against a database that has actually lost its schema, not reasoned about. An earlier attempt dropped the schema before the run and proved nothing — globalSetup re-migrates, so it repaired itself and every test passed. The suite drops and rebuilds around each case and restores in afterAll; the full integration suite was then run twice to confirm the restore holds for everything ordered after it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-02 17:51:43 -05:00
co-authored by Claude Opus 5
parent a02214108a
commit aeee4ecd2c
3 changed files with 169 additions and 7 deletions
@@ -25,7 +25,14 @@ async function waitForDb(retries = 20): Promise<void> {
export default async function globalSetup(): Promise<void> {
await waitForDb();
const { migrate, closeDb } = await import('./testDb');
const { migrate, closeDb, assertSchemaPresent } = await import('./testDb');
await migrate();
// Cheap, once, and it establishes the fact the rest of the run depends on:
// the schema was here when we started. Without it, a run that never had a
// schema and a run that lost one midway are indistinguishable from the
// failures they produce. See #154.
await assertSchemaPresent('immediately after migrating');
await closeDb();
}