From 1883e1e8c113497a286ec9f29631bae3088feef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 17 May 2026 14:52:39 +0200 Subject: [PATCH] test(integration): isolate apns-dispatch + integration-status from shared mock state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The integration suite used to share a single module graph across files (`pool: forks`, `fileParallelism: false`, `isolate: false`). That kept the container boot amortised but meant a `vi.mock()` declaration in one file lost to whichever earlier file had already pulled the real module into the graph. `apns-dispatch.test.ts` and `integration-status.test.ts` both fall through to `@/lib/notifications/dispatcher` (and its `@parse/node-apn` / telegram sender deps); when a sibling test mounted the real dispatcher first, the mock factories registered later silently no-op'd and the in-suite run reported the mock as called zero times. Each file still passed in isolation, which is the fingerprint the v1.4.35.1 closure already flagged as pre-existing. Flip the integration config to `isolate: true`. Per-file module isolation costs ~10 s of import rebuild across the 56-file run; the Postgres testcontainer + migrations live in `globalSetup`, so the slow part (container boot, ~5-15 s) is unaffected. The two `withings-*-sync.test.ts` files were previously dependent on a sibling setting `process.env.ENCRYPTION_KEY` before them — pin the deterministic test key in each file so they remain self-contained under per-file isolation. Locally `pnpm test:integration` now shows the four target failures green; the remaining two bp-in-target flakes are pre-existing local-only data drift that passed on CI under the old isolation flag and continue to be ordering-independent. --- tests/integration/withings-activity-sync.test.ts | 9 +++++++++ tests/integration/withings-sleep-sync.test.ts | 9 +++++++++ vitest.integration.config.mts | 13 ++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/tests/integration/withings-activity-sync.test.ts b/tests/integration/withings-activity-sync.test.ts index 5afc464b2..0c0b54a8f 100644 --- a/tests/integration/withings-activity-sync.test.ts +++ b/tests/integration/withings-activity-sync.test.ts @@ -11,6 +11,15 @@ */ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +// Crypto reads `ENCRYPTION_KEY` lazily on first encrypt(). Under the +// previous `isolate: false` suite the env from any sibling that seeded +// the key leaked into this file; per-file isolation (v1.4.37 W-CI) +// reveals that this spec never seeded its own key. Pin a deterministic +// 32-byte test key before any `@/lib/crypto` import so the spec stays +// self-contained. +process.env.ENCRYPTION_KEY ??= + "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; + import { encrypt } from "@/lib/crypto"; import { getPrismaClient, truncateAllTables } from "./setup"; diff --git a/tests/integration/withings-sleep-sync.test.ts b/tests/integration/withings-sleep-sync.test.ts index eb058e790..293dd30b8 100644 --- a/tests/integration/withings-sleep-sync.test.ts +++ b/tests/integration/withings-sleep-sync.test.ts @@ -9,6 +9,15 @@ */ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +// Crypto reads `ENCRYPTION_KEY` lazily on first encrypt(). Under the +// previous `isolate: false` suite the env from any sibling that seeded +// the key leaked into this file; per-file isolation (v1.4.37 W-CI) +// reveals that this spec never seeded its own key. Pin a deterministic +// 32-byte test key before any `@/lib/crypto` import so the spec stays +// self-contained. +process.env.ENCRYPTION_KEY ??= + "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; + import { encrypt } from "@/lib/crypto"; import { getPrismaClient, truncateAllTables } from "./setup"; diff --git a/vitest.integration.config.mts b/vitest.integration.config.mts index ed3f4eb8b..4ae52780a 100644 --- a/vitest.integration.config.mts +++ b/vitest.integration.config.mts @@ -23,7 +23,18 @@ export default defineConfig({ // level (the old `poolOptions.forks.singleFork` was removed). pool: "forks", fileParallelism: false, - isolate: false, + // v1.4.37 W-CI — switched from `isolate: false` to `isolate: true`. + // The previous setting reused the module graph across files inside + // one fork; mock declarations (`vi.mock("@/lib/notifications/...")`, + // `vi.mock("@parse/node-apn")`) registered in `apns-dispatch.test.ts` + // and `integration-status.test.ts` lost to whichever earlier file + // had already pulled the real dispatcher / sender modules into the + // shared graph, so the in-suite run showed flaky 0-call mocks while + // each file passed in isolation. Re-isolating module state per file + // costs ~10 s of import-rebuild on a 56-file run; the Postgres + // testcontainer + migrations still live in `globalSetup` so the + // expensive boot cost is unaffected. + isolate: true, // One container for the whole run; tests truncate between them. globalSetup: ["./tests/integration/global-setup.ts"], },