experimental-test-module-mocks with ES imports does not reset mocked modules for tests in the same file
Personne n'a encore pris cette issue.
- Langage dominant
- JavaScript
- Étoiles
- 122k
- Forks
- 37.4k
- Merge moyen
- 4 j 2 h
- PR mergées (30 j)
- 283
Description
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?
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez par exécuter la reproduction dans test/cache-issue.test.js avec node --test --experimental-test-module-mocks. Lisez le comportement de node:test concernant le mocking des modules mis en œuvre par t.mock.module() et mock.restoreAll(), ainsi que les imports de file-processor.js et fs-wrapper.js. C’est terminé lorsque le deuxième test reçoit son propre mock sans le paramètre de requête de contournement du cache, tandis que les tests existants continuent de réussir.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- javascript, node.js
- Domaine
- backend, testing
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- Calme
- Clarté
- Plutôt claire
- Accessibilité débutants
- 48/100