From dceac65ab8d4dbc9b0f9889f766fc0ffdb2bb01b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Mon, 15 Jun 2026 22:04:07 +0200 Subject: [PATCH] test(modules): stub the module gate in doctor-report and export suites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v1.18.0 per-user module gate reads the database to resolve a user's module map. Three pre-existing aggregator/route test suites — the doctor-report PDF route, the health-record export route, and the export soft-delete filter — exercise paths that now call resolveModuleMap / requireModuleEnabled but never mocked the gate, so its DB read threw and the route returned 500. Stub the gate to all-modules-enabled (an empty map is default-on) in each file, re-asserting the return values in the mock-resetting beforeEach, mirroring the snapshot suite's existing pattern. --- .../doctor-report/__tests__/pdf-route.test.ts | 26 +++++++++++++++++++ .../__tests__/soft-delete-filter.test.ts | 21 +++++++++++++++ .../health-record/__tests__/route.test.ts | 22 ++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/src/app/api/doctor-report/__tests__/pdf-route.test.ts b/src/app/api/doctor-report/__tests__/pdf-route.test.ts index 50fb75504..e95d87afc 100644 --- a/src/app/api/doctor-report/__tests__/pdf-route.test.ts +++ b/src/app/api/doctor-report/__tests__/pdf-route.test.ts @@ -39,11 +39,36 @@ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn(), })); +// v1.18.0 — the doctor-report aggregator resolves the per-user module map +// so a disabled data-domain module never reaches the report. Stub the gate +// to "all modules enabled" (an empty map ⇒ default-on) so these pre-existing +// route tests don't stand up the real gate's DB reads. +vi.mock("@/lib/modules/gate", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + resolveModuleMap: vi.fn(), + isModuleEnabled: vi.fn(), + requireModuleEnabled: vi.fn(), + }; +}); + import { POST } from "../pdf/route"; import { prisma } from "@/lib/db"; import { getSession } from "@/lib/auth/session"; import { checkRateLimit } from "@/lib/rate-limit"; import { auditLog } from "@/lib/auth/audit"; +import { + resolveModuleMap, + isModuleEnabled, + requireModuleEnabled, +} from "@/lib/modules/gate"; + +function setModuleGateAllEnabled() { + vi.mocked(resolveModuleMap).mockResolvedValue({} as never); + vi.mocked(isModuleEnabled).mockResolvedValue(true); + vi.mocked(requireModuleEnabled).mockResolvedValue({ enabled: true } as never); +} function makeRequest( body?: Record, @@ -86,6 +111,7 @@ function setEmptyDataMocks() { describe("POST /api/doctor-report/pdf", () => { beforeEach(() => { vi.resetAllMocks(); + setModuleGateAllEnabled(); }); it("returns 401 when not authenticated", async () => { diff --git a/src/app/api/export/__tests__/soft-delete-filter.test.ts b/src/app/api/export/__tests__/soft-delete-filter.test.ts index 04e454684..71c6842dc 100644 --- a/src/app/api/export/__tests__/soft-delete-filter.test.ts +++ b/src/app/api/export/__tests__/soft-delete-filter.test.ts @@ -51,9 +51,27 @@ vi.mock("@/lib/tz/resolver", () => ({ resolveUserTimezone: vi.fn().mockResolvedValue("Europe/Berlin"), })); +// v1.18.0 — the achievements route gates on `requireModuleEnabled`. Stub +// the gate to "all modules enabled" (an empty map ⇒ default-on) so this +// pre-existing soft-delete test doesn't stand up the real gate's DB reads. +vi.mock("@/lib/modules/gate", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + resolveModuleMap: vi.fn(), + isModuleEnabled: vi.fn(), + requireModuleEnabled: vi.fn(), + }; +}); + import { prisma } from "@/lib/db"; import { getSession } from "@/lib/auth/session"; import { checkRateLimit } from "@/lib/rate-limit"; +import { + resolveModuleMap, + isModuleEnabled, + requireModuleEnabled, +} from "@/lib/modules/gate"; const SESSION_OK = { user: { @@ -69,6 +87,9 @@ function mkReq(url: string): NextRequest { beforeEach(() => { vi.clearAllMocks(); + vi.mocked(resolveModuleMap).mockResolvedValue({} as never); + vi.mocked(isModuleEnabled).mockResolvedValue(true); + vi.mocked(requireModuleEnabled).mockResolvedValue({ enabled: true } as never); vi.mocked(getSession).mockResolvedValue(SESSION_OK as never); vi.mocked(checkRateLimit).mockResolvedValue({ allowed: true, diff --git a/src/app/api/export/health-record/__tests__/route.test.ts b/src/app/api/export/health-record/__tests__/route.test.ts index bc8e1a7c0..837913e89 100644 --- a/src/app/api/export/health-record/__tests__/route.test.ts +++ b/src/app/api/export/health-record/__tests__/route.test.ts @@ -32,9 +32,28 @@ vi.mock("@/lib/tz/resolver", () => ({ resolveUserTimezone: vi.fn().mockResolvedValue("Europe/Berlin"), })); +// v1.18.0 — the health-record aggregator resolves the per-user module map +// so a disabled data-domain module never reaches the export. Stub the gate +// to "all modules enabled" (an empty map ⇒ default-on) so these pre-existing +// route tests don't stand up the real gate's DB reads. +vi.mock("@/lib/modules/gate", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + resolveModuleMap: vi.fn(), + isModuleEnabled: vi.fn(), + requireModuleEnabled: vi.fn(), + }; +}); + import { prisma } from "@/lib/db"; import { getSession } from "@/lib/auth/session"; import { checkRateLimit } from "@/lib/rate-limit"; +import { + resolveModuleMap, + isModuleEnabled, + requireModuleEnabled, +} from "@/lib/modules/gate"; const SESSION_OK = { user: { id: "user-1", email: "test@example.com", role: "USER" }, @@ -63,6 +82,9 @@ async function pdfText(res: Response): Promise { beforeEach(() => { vi.clearAllMocks(); + vi.mocked(resolveModuleMap).mockResolvedValue({} as never); + vi.mocked(isModuleEnabled).mockResolvedValue(true); + vi.mocked(requireModuleEnabled).mockResolvedValue({ enabled: true } as never); vi.mocked(getSession).mockResolvedValue(SESSION_OK as never); vi.mocked(checkRateLimit).mockResolvedValue({ allowed: true,