Fix flaky download.test.js caused by leaked URL mock across test files - #1698
Conversation
img.test.js and eventMapIcons.test.js replaced global.URL.createObjectURL/ revokeObjectURL via direct assignment instead of jest.spyOn, so jest.restoreAllMocks() could never undo it. Since jest-fixed-jsdom binds window.URL to Node's real process-wide singleton, the leaked mock persisted across test files in the same worker, silently accumulating unrelated calls that download.test.js's spy would inherit and misread as its own. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Fixes intermittent Jest CI failures caused by leaking URL.createObjectURL / URL.revokeObjectURL mocks across test files in the same worker process. This aligns with the codebase’s testing approach by ensuring global browser APIs are mocked via spies that jest.restoreAllMocks() can reliably undo.
Changes:
- Replaced direct
global.URL.* = jest.fn()assignments withjest.spyOn(...).mockImplementation(...)in affected tests. - Added a
jest.restoreAllMocks()cleanup inimg.test.jsto ensure the URL spies are restored after the suite completes.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/utils/img.test.js | Switches URL mocks to spies and adds teardown to prevent cross-file leakage. |
| src/utils/eventMapIcons.test.js | Switches URL mocks to spies so jest.restoreAllMocks() can properly restore globals after each test. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| jest.spyOn(global.URL, 'createObjectURL').mockImplementation(() => {}); | ||
| jest.spyOn(global.URL, 'revokeObjectURL').mockImplementation(() => {}); | ||
|
|
||
| global.Image = jest.fn(() => ({ | ||
| setAttribute: jest.fn(), |
luixlive
left a comment
There was a problem hiding this comment.
Approved. Probably worth doing what Copilot suggests for scalability.
i chatted it with Claude, and it seems like the pattern is right, but it's not really a concern since internally here Claude's take:
|
Summary
src/utils/download.test.jswhereblob.typeassertions randomly received a wrong MIME type (e.g.text/javascript,image/jpeginstead oftext/plain/application/json).img.test.jsandeventMapIcons.test.jsreplacedglobal.URL.createObjectURL/revokeObjectURLvia direct assignment (global.URL.createObjectURL = jest.fn()) instead ofjest.spyOn.jest.restoreAllMocks()can only undo spies, not plain assignments, so the mock permanently replaced the real implementation for the rest of that Jest worker process. Becausejest-fixed-jsdombindswindow.URLto Node's actual process-wide singleton class (not a per-file copy), this leaked mock silently accumulated calls from other test files. Whendownload.test.jsspied on the same (already-mocked) function, it inherited those stale calls, somock.calls[0]sometimes pointed at another test's call instead of its own.jest.spyOn(...).mockImplementation(...), whichjest.restoreAllMocks()(already called inafterEach/addedafterAll) can properly undo.Test plan
yarn jest src/utils/img.test.js src/utils/eventMapIcons.test.js src/utils/download.test.js— all passyarn test-ci) 6 consecutive times after the fix — all green, no recurrenceeslinton both changed files — no new issues introduced🤖 Generated with Claude Code