From f78b31b3dc613e7d105eb91936fc05b6de4a374d Mon Sep 17 00:00:00 2001 From: Dan Knauss <273554+dknauss@users.noreply.github.com> Date: Sat, 26 Sep 2026 09:50:37 -0600 Subject: [PATCH] test: reset shared mock state so unit tests pass under --randomize Three within-file order dependencies surfaced by `wp-scripts test-unit-js --randomize` (e.g. seeds -1645434887, 1761699380, 1): - edit.test.js: the mocked @wordpress/data notices store was reset only in the "Edit focus management" block, so a leftover notice added a second Dismiss button to the OSCOLA and soft-cap dismissal tests. Reset it in a file-level beforeEach. - parser.test.js: "PMID fallback resolution" resets the module registry, so parser's lazy import('./formatting/csl') later got a fresh mock the file's assertions never saw, and api-fetch was left un-mocked. Its afterEach now re-points the registry at the original mock instances. - use-citation-editor-state.test.js: race tests queue a pending formatBibliographyEntries once-value the save never reaches, and clearAllMocks does not drop once-queues. mockReset it in beforeEach. Co-Authored-By: Claude Opus 5.5 --- src/edit.test.js | 8 +++++++- src/hooks/use-citation-editor-state.test.js | 4 ++++ src/lib/parser.test.js | 11 ++++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/edit.test.js b/src/edit.test.js index 51e38fa..1756490 100644 --- a/src/edit.test.js +++ b/src/edit.test.js @@ -563,6 +563,13 @@ function createCitation({ }; } +// The mocked notices store is module-level state shared by every render in +// this file; reset it per test so a notice left by one test (and its Dismiss +// button) never leaks into another under --randomize. +beforeEach(() => { + require('@wordpress/data').__unstableResetNotices(); +}); + describe('Edit focus management', () => { beforeEach(() => { jest.clearAllMocks(); @@ -575,7 +582,6 @@ describe('Edit focus management', () => { downloadCslJsonExport.mockReset(); downloadRisExport.mockReset(); copyTextToClipboard.mockReset(); - require('@wordpress/data').__unstableResetNotices(); }); it('shows DOI/BibTeX-only guidance when parsing fails without entries', async () => { diff --git a/src/hooks/use-citation-editor-state.test.js b/src/hooks/use-citation-editor-state.test.js index 1ad6f75..f99e999 100644 --- a/src/hooks/use-citation-editor-state.test.js +++ b/src/hooks/use-citation-editor-state.test.js @@ -111,6 +111,10 @@ function makeHookArgs(citations = [makeCitation()]) { beforeEach(() => { jest.clearAllMocks(); + // mockReset (not just clearAllMocks) drops queued *Once values: several + // race tests queue a pending format result the save never reaches, which + // would otherwise be handed to whichever test calls the formatter next. + formatBibliographyEntries.mockReset(); formatBibliographyEntries.mockImplementation((items) => items.map(() => 'Reformatted entry') ); diff --git a/src/lib/parser.test.js b/src/lib/parser.test.js index 76a9ae4..28f7a62 100644 --- a/src/lib/parser.test.js +++ b/src/lib/parser.test.js @@ -25,6 +25,11 @@ import { } from './parser'; import { formatBibliographyEntries } from './formatting/csl'; +// parsePastedInput lazily imports './formatting/csl' at call time, so the +// module registry must keep resolving to these file-level mock instances. +const formattingCslMock = jest.requireMock('./formatting/csl'); +const apiFetchMock = jest.requireMock('@wordpress/api-fetch'); + describe('validateAndSanitizeCsl', () => { it('sanitizes nested values and normalizes issued date-parts', () => { const sanitized = validateAndSanitizeCsl({ @@ -1458,8 +1463,12 @@ describe('PMID fallback resolution', () => { } afterEach(() => { + // Undo mockParserDependencies: after resetModules the registry would + // hand parser's lazy import a fresh formatter mock the other tests in + // this file never see, and api-fetch would stay mocked as undefined. jest.resetModules(); - jest.dontMock('@wordpress/api-fetch'); + jest.doMock('./formatting/csl', () => formattingCslMock); + jest.doMock('@wordpress/api-fetch', () => apiFetchMock); }); it('falls back to window.fetch when the WordPress REST helper is unavailable', async () => {