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
This commit is contained in:
jubnl
2026-04-07 23:32:22 +02:00
parent e991f834e2
commit f594cbc21b
2 changed files with 9 additions and 18 deletions
+5 -4
View File
@@ -59,10 +59,11 @@ globalThis.ResizeObserver = vi.fn().mockImplementation(() => ({
disconnect: vi.fn(), disconnect: vi.fn(),
})) as unknown as typeof ResizeObserver; })) as unknown as typeof ResizeObserver;
// URL.createObjectURL / revokeObjectURL — jsdom defines these but returns '' for createObjectURL; // URL.createObjectURL / revokeObjectURL — in jsdom, modules access globals
// always override so tests get a predictable 'blob:mock' string. // through window.URL (not globalThis.URL — these are different objects on CI).
Object.defineProperty(URL, 'createObjectURL', { writable: true, configurable: true, value: vi.fn(() => 'blob:mock') }); // Targeting window.URL is required so the mock is visible to source modules.
Object.defineProperty(URL, 'revokeObjectURL', { writable: true, configurable: true, value: vi.fn() }); 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 — jsdom doesn't implement it
Element.prototype.scrollIntoView = vi.fn(); Element.prototype.scrollIntoView = vi.fn();
+4 -14
View File
@@ -8,19 +8,9 @@ const flushPromises = () => new Promise<void>(r => setTimeout(r, 10));
beforeEach(() => { beforeEach(() => {
clearImageQueue(); clearImageQueue();
vi.restoreAllMocks(); // restore any vi.spyOn() wrappers from the previous test vi.restoreAllMocks(); // remove vi.spyOn() wrappers, restoring to the setup.ts vi.fn()
vi.unstubAllGlobals(); // restore any vi.stubGlobal() replacements from the previous test vi.clearAllMocks(); // reset accumulated call counts on window.URL mocks from setup.ts
vi.unstubAllGlobals();
// 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);
}); });
// ── getAuthUrl ───────────────────────────────────────────────────────────────── // ── getAuthUrl ─────────────────────────────────────────────────────────────────
@@ -204,7 +194,7 @@ describe('clearImageQueue', () => {
describe('FE-COMP-AUTHURL-012: clearImageQueue discards pending entries', () => { describe('FE-COMP-AUTHURL-012: clearImageQueue discards pending entries', () => {
it('removes queued items so they never execute after active slots drain', async () => { it('removes queued items so they never execute after active slots drain', async () => {
const resolvers: Array<() => void> = []; const resolvers: Array<() => void> = [];
const createObjectURLSpy = vi.spyOn(URL, 'createObjectURL'); const createObjectURLSpy = vi.spyOn(window.URL, 'createObjectURL');
vi.spyOn(globalThis, 'fetch').mockImplementation(async () => { vi.spyOn(globalThis, 'fetch').mockImplementation(async () => {
await new Promise<void>(r => resolvers.push(r)); await new Promise<void>(r => resolvers.push(r));