diff --git a/packages/metro-file-map/src/plugins/MockPlugin.js b/packages/metro-file-map/src/plugins/MockPlugin.js index 805c0c5bb1..98e119f744 100644 --- a/packages/metro-file-map/src/plugins/MockPlugin.js +++ b/packages/metro-file-map/src/plugins/MockPlugin.js @@ -147,13 +147,18 @@ export default class MockPlugin const duplicates = this.#raw.duplicates.get(mockName); if (duplicates != null) { const posixRelativePath = normalizePathSeparatorsToPosix(canonicalPath); + const wasActiveMock = this.#raw.mocks.get(mockName) === posixRelativePath; duplicates.delete(posixRelativePath); if (duplicates.size === 1) { this.#raw.duplicates.delete(mockName); } - // Set the mock to a remaining duplicate. Should never be empty. - const remaining = nullthrows(duplicates.values().next().value); - this.#raw.mocks.set(mockName, remaining); + // Only reassign the active mock if the file we removed *was* the active + // one; otherwise a non-active duplicate's removal would clobber it. + if (wasActiveMock) { + // Set the mock to a remaining duplicate. Should never be empty. + const remaining = nullthrows(duplicates.values().next().value); + this.#raw.mocks.set(mockName, remaining); + } } else { this.#raw.mocks.delete(mockName); } diff --git a/packages/metro-file-map/src/plugins/mocks/__tests__/MockPlugin-test.js b/packages/metro-file-map/src/plugins/mocks/__tests__/MockPlugin-test.js index 43f2835646..36e95abf24 100644 --- a/packages/metro-file-map/src/plugins/mocks/__tests__/MockPlugin-test.js +++ b/packages/metro-file-map/src/plugins/mocks/__tests__/MockPlugin-test.js @@ -107,6 +107,25 @@ Duplicate manual mock found for \`foo\`: }); }); + test('removing a non-active duplicate keeps the active mock', () => { + onFileAdded(p('a/__mocks__/foo.js')); + onFileAdded(p('b/__mocks__/foo.js')); + onFileAdded(p('c/__mocks__/foo.js')); // latest wins -> active mock is c + + expect(mockMap.getMockModule('foo')).toBe(p('/root/c/__mocks__/foo.js')); + + // Remove a NON-active duplicate (b); the active mock (c) must be kept. + mockMap.onChanged({ + addedFiles: new Map(), + modifiedFiles: new Map(), + removedFiles: new Map([[p('b/__mocks__/foo.js'), null]]), + addedDirectories: new Set(), + removedDirectories: new Set(), + }); + + expect(mockMap.getMockModule('foo')).toBe(p('/root/c/__mocks__/foo.js')); + }); + test('loads from a snapshot', async () => { await mockMap.initialize({ files: {