Skip to content

Commit f629518

Browse files
test_runner: sync built-in ESM exports for mock timers
Synchronize ESM facades whenever mocked timers are enabled, disabled, or reset. This ensures that 'node:timers/promises' and other built-ins correctly reflect the mocked state when imported in ESM modules. Fixes: #62081
1 parent 8edeff9 commit f629518

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

lib/internal/test_runner/mock/mock_timers.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ const {
2424
validateNumber,
2525
validateStringArray,
2626
} = require('internal/validators');
27+
const { Module } = require('internal/modules/cjs/loader');
28+
const { syncBuiltinESMExports } = Module;
2729

2830
const {
2931
AbortError,
@@ -440,9 +442,9 @@ class MockTimers {
440442

441443
const eventIt = EventEmitter.on(emitter, 'data');
442444
const timer = this.#createTimer(true,
443-
() => emitter.emit('data'),
444-
interval,
445-
options);
445+
() => emitter.emit('data'),
446+
interval,
447+
options);
446448

447449
try {
448450
// eslint-disable-next-line no-unused-vars
@@ -628,6 +630,7 @@ class MockTimers {
628630
const target = activate ? options.toFake : options.toReal;
629631
ArrayPrototypeForEach(this.#timersInContext, (timer) => target[timer]());
630632
this.#isEnabled = activate;
633+
syncBuiltinESMExports();
631634
}
632635

633636
/**
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import '../common/index.mjs';
2+
import { describe, it } from 'node:test';
3+
import { setTimeout } from 'node:timers/promises';
4+
import assert from 'node:assert';
5+
6+
describe('Mock Timers ESM Regression', () => {
7+
it('should work with node:timers/promises and runAll() in ESM', async (t) => {
8+
t.mock.timers.enable({ apis: ['Date', 'setTimeout'] });
9+
const startTime = Date.now();
10+
let t1 = 0;
11+
12+
await Promise.all([
13+
(async () => {
14+
await setTimeout(1000);
15+
t1 = Date.now();
16+
})(),
17+
(async () => {
18+
// Wait for the next tick to ensure setTimeout has been called
19+
await new Promise((resolve) => process.nextTick(resolve));
20+
t.mock.timers.runAll();
21+
})(),
22+
]);
23+
24+
assert.strictEqual(t1 - startTime, 1000);
25+
});
26+
27+
it('should work with node:timers/promises and tick() in ESM', async (t) => {
28+
t.mock.timers.enable({ apis: ['Date', 'setTimeout'] });
29+
const startTime = Date.now();
30+
let t1 = 0;
31+
32+
await Promise.all([
33+
(async () => {
34+
await setTimeout(500);
35+
t1 = Date.now();
36+
})(),
37+
(async () => {
38+
await new Promise((resolve) => process.nextTick(resolve));
39+
t.mock.timers.tick(500);
40+
})(),
41+
]);
42+
43+
assert.strictEqual(t1 - startTime, 500);
44+
});
45+
});

0 commit comments

Comments
 (0)