From f594cbc21be3e470245de74e5b8e1c09268ca46c Mon Sep 17 00:00:00 2001 From: jubnl Date: Tue, 7 Apr 2026 23:32:22 +0200 Subject: [PATCH] fix(tests): target window.URL instead of URL for createObjectURL mocking In jsdom, source modules resolve bare 'URL' identifiers through window.URL (the jsdom window object), not through globalThis.URL (Node's URL class). On GitHub Actions these are distinct objects, so all prior attempts (Object.defineProperty, direct assignment, vi.stubGlobal) were patching the wrong object and failing silently. Changes: - setup.ts: Object.defineProperty targets window.URL so the vi.fn mock is visible to authUrl.ts at call time - authUrl.test.ts: drop vi.stubGlobal approach; add vi.clearAllMocks() to reset accumulated call counts on the setup.ts vi.fn between tests; fix vi.spyOn target to window.URL in test 012 --- client/tests/setup.ts | 9 +++++---- client/tests/unit/api/authUrl.test.ts | 18 ++++-------------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/client/tests/setup.ts b/client/tests/setup.ts index 0d6373e3..d801eee1 100644 --- a/client/tests/setup.ts +++ b/client/tests/setup.ts @@ -59,10 +59,11 @@ globalThis.ResizeObserver = vi.fn().mockImplementation(() => ({ disconnect: vi.fn(), })) as unknown as typeof ResizeObserver; -// URL.createObjectURL / revokeObjectURL — jsdom defines these but returns '' for createObjectURL; -// always override so tests get a predictable 'blob:mock' string. -Object.defineProperty(URL, 'createObjectURL', { writable: true, configurable: true, value: vi.fn(() => 'blob:mock') }); -Object.defineProperty(URL, 'revokeObjectURL', { writable: true, configurable: true, value: vi.fn() }); +// URL.createObjectURL / revokeObjectURL — in jsdom, modules access globals +// through window.URL (not globalThis.URL — these are different objects on CI). +// Targeting window.URL is required so the mock is visible to source modules. +Object.defineProperty(window.URL, 'createObjectURL', { writable: true, configurable: true, value: vi.fn(() => 'blob:mock') }); +Object.defineProperty(window.URL, 'revokeObjectURL', { writable: true, configurable: true, value: vi.fn() }); // Element.prototype.scrollIntoView — jsdom doesn't implement it Element.prototype.scrollIntoView = vi.fn(); diff --git a/client/tests/unit/api/authUrl.test.ts b/client/tests/unit/api/authUrl.test.ts index c0906b2b..c7e68362 100644 --- a/client/tests/unit/api/authUrl.test.ts +++ b/client/tests/unit/api/authUrl.test.ts @@ -8,19 +8,9 @@ const flushPromises = () => new Promise(r => setTimeout(r, 10)); beforeEach(() => { clearImageQueue(); - vi.restoreAllMocks(); // restore any vi.spyOn() wrappers from the previous test - vi.unstubAllGlobals(); // restore any vi.stubGlobal() replacements from the previous test - - // jsdom's URL.createObjectURL is non-writable/non-configurable in some CI - // environments — direct assignment and Object.defineProperty both fail - // silently. vi.stubGlobal replaces globalThis.URL entirely, which always - // works. We extend the real URL so all URL parsing behaviour is preserved. - const OriginalURL = URL; - class TestURL extends OriginalURL { - static createObjectURL = vi.fn(() => 'blob:mock'); - static revokeObjectURL = vi.fn(); - } - vi.stubGlobal('URL', TestURL); + vi.restoreAllMocks(); // remove vi.spyOn() wrappers, restoring to the setup.ts vi.fn() + vi.clearAllMocks(); // reset accumulated call counts on window.URL mocks from setup.ts + vi.unstubAllGlobals(); }); // ── getAuthUrl ───────────────────────────────────────────────────────────────── @@ -204,7 +194,7 @@ describe('clearImageQueue', () => { describe('FE-COMP-AUTHURL-012: clearImageQueue discards pending entries', () => { it('removes queued items so they never execute after active slots drain', async () => { const resolvers: Array<() => void> = []; - const createObjectURLSpy = vi.spyOn(URL, 'createObjectURL'); + const createObjectURLSpy = vi.spyOn(window.URL, 'createObjectURL'); vi.spyOn(globalThis, 'fetch').mockImplementation(async () => { await new Promise(r => resolvers.push(r));