From ad7507d133b62e0240f9bf00e7a4e1872d8f5f4d Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Mon, 9 Mar 2026 03:08:15 -0500 Subject: [PATCH] fix: use real cache key prefixes in mock and dynamic imports for CI compatibility --- tests/unit/cwOpportunityService.test.ts | 25 +++++++++++++++++-------- tests/unit/opportunitiesManager.test.ts | 18 +++++++++--------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/tests/unit/cwOpportunityService.test.ts b/tests/unit/cwOpportunityService.test.ts index 8daa589..881a7aa 100644 --- a/tests/unit/cwOpportunityService.test.ts +++ b/tests/unit/cwOpportunityService.test.ts @@ -1,8 +1,8 @@ -import { describe, test, expect, mock, beforeEach } from "bun:test"; +import { describe, test, expect, mock, beforeAll, beforeEach } from "bun:test"; // --------------------------------------------------------------------------- -// Top-level mocks — configured before the module is imported so the ESM -// linker always sees the mocked version, regardless of Bun's module cache. +// Top-level mocks — must be registered before any import of the service +// module so the ESM linker resolves mocked dependencies. // --------------------------------------------------------------------------- const postMock = mock(() => Promise.resolve({ data: { id: 9001 } })); @@ -22,11 +22,20 @@ mock.module("../../src/modules/cw-utils/opportunities/opportunities", () => ({ opportunityCw: { update: updateMock }, })); -// Import AFTER mocks -import { - submitTimeEntry, - syncOpportunityStatus, -} from "../../src/services/cw.opportunityService"; +// --------------------------------------------------------------------------- +// Dynamic import — use await import() inside beforeAll so the module is +// loaded AFTER mock.module calls take effect. Static imports are hoisted +// above top-level code in some Bun versions, defeating the mock. +// --------------------------------------------------------------------------- + +let submitTimeEntry: typeof import("../../src/services/cw.opportunityService")["submitTimeEntry"]; +let syncOpportunityStatus: typeof import("../../src/services/cw.opportunityService")["syncOpportunityStatus"]; + +beforeAll(async () => { + const mod = await import("../../src/services/cw.opportunityService"); + submitTimeEntry = mod.submitTimeEntry; + syncOpportunityStatus = mod.syncOpportunityStatus; +}); // --------------------------------------------------------------------------- // Tests diff --git a/tests/unit/opportunitiesManager.test.ts b/tests/unit/opportunitiesManager.test.ts index b101071..7030001 100644 --- a/tests/unit/opportunitiesManager.test.ts +++ b/tests/unit/opportunitiesManager.test.ts @@ -33,16 +33,16 @@ function createStablePrismaMock( * (some Bun versions do not enumerate Proxy keys for static imports). */ function buildCacheMock(overrides: Record = {}) { - const keyFn = (...args: any[]) => `mock:key:${args.join(":")}`; return { - // Key helpers - activityCacheKey: mock(keyFn), - companyCwCacheKey: mock(keyFn), - notesCacheKey: mock(keyFn), - contactsCacheKey: mock(keyFn), - productsCacheKey: mock(keyFn), - siteCacheKey: mock(keyFn), - oppCwDataCacheKey: mock(keyFn), + // Key helpers — use real prefixes so cross-file mock leaks don't + // break opportunityCache.test.ts key assertions. + activityCacheKey: mock((id: number) => `opp:activities:${id}`), + companyCwCacheKey: mock((id: number) => `opp:company-cw:${id}`), + notesCacheKey: mock((id: number) => `opp:notes:${id}`), + contactsCacheKey: mock((id: number) => `opp:contacts:${id}`), + productsCacheKey: mock((id: number) => `opp:products:${id}`), + siteCacheKey: mock((a: number, b: number) => `opp:site:${a}:${b}`), + oppCwDataCacheKey: mock((id: number) => `opp:cw-data:${id}`), // Read helpers getCachedActivities: mock(() => Promise.resolve(null)), getCachedCompanyCwData: mock(() => Promise.resolve(null)),