experimental-test-module-mocks with ES imports does not reset mocked modules for tests in the same file
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- JavaScript
- Sterne
- 122k
- Forks
- 37.3k
- Ø Merge
- 4 T. 2 Std.
- Gemergte PRs (30 T.)
- 283
Beschreibung
Version
24.4.1
Platform
Microsoft Windows NT 10.0.26100.0 x64
Subsystem
node:test
What steps will reproduce the bug?
// file1: utils/fs-wrapper.js
// Simple wrapper around fs.readFileSync to demonstrate the issue
import { readFileSync } from 'node:fs';
export default function readFile(path: string): string {
return readFileSync(path, 'utf8');
}
// file2: utils/file-processor.js
// Module that depends on fs-wrapper
import readFile from './fs-wrapper.js';
export default function processFile(path: string): string {
const content = readFile(path);
return content.toUpperCase();
}
// file3: test/cache-issue.test.js
// Test demonstrating the ES module cache issue
import { test, describe, beforeEach, mock } from 'node:test';
import assert from 'node:assert/strict';
describe('ES Module Cache Issue with mock.restoreAll()', () => {
beforeEach(() => {
mock.restoreAll();
});
test('first test - should use mock', async (t) => {
// Mock the fs-wrapper module
const mockReadFile = mock.fn(() => 'mocked content from test 1');
t.mock.module('../utils/fs-wrapper.js', {
defaultExport: mockReadFile,
});
// Import the module that depends on fs-wrapper
const fileProcessorModule = await import('../utils/file-processor.js');
const processFile = fileProcessorModule.default;
const result = processFile('dummy-path.txt');
assert.strictEqual(result, 'MOCKED CONTENT FROM TEST 1');
assert.strictEqual(mockReadFile.mock.callCount(), 1);
});
test('second test - should use different mock but fails due to cache', async (t) => {
// Mock with different return value
const mockReadFile = mock.fn(() => 'mocked content from test 2');
t.mock.module('../utils/fs-wrapper.js', {
defaultExport: mockReadFile,
});
// This import returns cached version that still references the old mock
const fileProcessorModule = await import('../utils/file-processor.js');
const processFile = fileProcessorModule.default;
const result = processFile('dummy-path.txt');
// This assertion will fail because the cached module still uses the old mock
assert.strictEqual(result, 'MOCKED CONTENT FROM TEST 2');
assert.strictEqual(mockReadFile.mock.callCount(), 1);
});
test('third test - workaround with cache busting', async (t) => {
// Mock with third return value
const mockReadFile = mock.fn(() => 'mocked content from test 3');
t.mock.module('../utils/fs-wrapper.js', {
defaultExport: mockReadFile,
});
// Use cache busting query parameter to force fresh import
const fileProcessorModule = await import('../utils/file-processor.js?v=' + Date.now());
const processFile = fileProcessorModule.default;
const result = processFile('dummy-path.txt');
// This assertion passes because we bypassed the cache
assert.strictEqual(result, 'MOCKED CONTENT FROM TEST 3');
assert.strictEqual(mockReadFile.mock.callCount(), 1);
});
});
// Command line: node --test --experimental-test-module-mocks
How often does it reproduce? Is there a required condition?
Every time.
What is the expected behavior? Why is that the expected behavior?
The mocked module should reset between tests.
What do you see instead?
▶ ES Module Cache Issue with mock.restoreAll()
✔ first test - should use mock (43.5241ms)
✖ second test - should use different mock but fails due to cache (3.0297ms)
✔ third test - workaround with cache busting (4.2197ms)
✖ ES Module Cache Issue with mock.restoreAll() (52.1751ms)
ℹ tests 6
ℹ suites 1
ℹ pass 5
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 137.1057
✖ failing tests:
test at dist\tests\file-processor.test.js:22:5
✖ second test - should use different mock but fails due to cache (3.0297ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
actual expected
at TestContext.<anonymous> (file:///C:/Users/xxx/Documents/GitHub/genesys-concepts/dist/tests/file-processor.test.js:34:16)
at async Test.run (node:internal/test_runner/test:1069:7)
at async Suite.processPendingSubtests (node:internal/test_runner/test:752:7) {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: 'MOCKED CONTENT FROM TEST 1',
expected: 'MOCKED CONTENT FROM TEST 2',
operator: 'strictEqual'
}
Additional information
Not sure if there is a better workaround for this or maybe I'm doing something wrong?
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne damit, die Reproduktion in test/cache-issue.test.js mit node --test --experimental-test-module-mocks auszuführen. Lies das von t.mock.module() und mock.restoreAll() getestete node:test-Verhalten beim Mocking von Modulen sowie die Imports von file-processor.js und fs-wrapper.js. Fertig ist die Änderung, wenn der zweite Test seinen eigenen Mock ohne den Cache-Busting-Query-Parameter erhält und die bestehenden Tests weiterhin erfolgreich sind.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- javascript, node.js
- Bereich
- backend, testing
- Issue-Typ
- Bug
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Aktivitätsstatus
- Ruhig
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 48/100