fix: use real cache key prefixes in mock and dynamic imports for CI compatibility

This commit is contained in:
2026-03-09 03:08:15 -05:00
parent 15ef24eb3e
commit ad7507d133
2 changed files with 26 additions and 17 deletions
+17 -8
View File
@@ -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 // Top-level mocks — must be registered before any import of the service
// linker always sees the mocked version, regardless of Bun's module cache. // module so the ESM linker resolves mocked dependencies.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const postMock = mock(() => Promise.resolve({ data: { id: 9001 } })); const postMock = mock(() => Promise.resolve({ data: { id: 9001 } }));
@@ -22,11 +22,20 @@ mock.module("../../src/modules/cw-utils/opportunities/opportunities", () => ({
opportunityCw: { update: updateMock }, opportunityCw: { update: updateMock },
})); }));
// Import AFTER mocks // ---------------------------------------------------------------------------
import { // Dynamic import — use await import() inside beforeAll so the module is
submitTimeEntry, // loaded AFTER mock.module calls take effect. Static imports are hoisted
syncOpportunityStatus, // above top-level code in some Bun versions, defeating the mock.
} from "../../src/services/cw.opportunityService"; // ---------------------------------------------------------------------------
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 // Tests
+9 -9
View File
@@ -33,16 +33,16 @@ function createStablePrismaMock(
* (some Bun versions do not enumerate Proxy keys for static imports). * (some Bun versions do not enumerate Proxy keys for static imports).
*/ */
function buildCacheMock(overrides: Record<string, any> = {}) { function buildCacheMock(overrides: Record<string, any> = {}) {
const keyFn = (...args: any[]) => `mock:key:${args.join(":")}`;
return { return {
// Key helpers // Key helpers — use real prefixes so cross-file mock leaks don't
activityCacheKey: mock(keyFn), // break opportunityCache.test.ts key assertions.
companyCwCacheKey: mock(keyFn), activityCacheKey: mock((id: number) => `opp:activities:${id}`),
notesCacheKey: mock(keyFn), companyCwCacheKey: mock((id: number) => `opp:company-cw:${id}`),
contactsCacheKey: mock(keyFn), notesCacheKey: mock((id: number) => `opp:notes:${id}`),
productsCacheKey: mock(keyFn), contactsCacheKey: mock((id: number) => `opp:contacts:${id}`),
siteCacheKey: mock(keyFn), productsCacheKey: mock((id: number) => `opp:products:${id}`),
oppCwDataCacheKey: mock(keyFn), siteCacheKey: mock((a: number, b: number) => `opp:site:${a}:${b}`),
oppCwDataCacheKey: mock((id: number) => `opp:cw-data:${id}`),
// Read helpers // Read helpers
getCachedActivities: mock(() => Promise.resolve(null)), getCachedActivities: mock(() => Promise.resolve(null)),
getCachedCompanyCwData: mock(() => Promise.resolve(null)), getCachedCompanyCwData: mock(() => Promise.resolve(null)),