node
node copied to clipboard
test_runner: check if timeout was cleared by own callback
Fixes calling clearTimeout
in a mocked setTimeout
callback resulting in two timeouts being removed from the execution queue (the current timeout and the next one in the queue). This happens because clearTimeout
removes the timeout at execution queue position 1, followed by the call in tick()
to #executionQueue.shift()
removing the next item in the queue.
I fixed this by checking if the first item in the execution queue has the same ID as the one that is being executed before calling #executionQueue.shift()
. If the IDs aren't the same, it means it was already removed by a call to clearTimeout
in the callback.
test('should not affect other timers when clearing timeout inside own callback', (t) => {
t.mock.timers.enable({ apis: ['setTimeout'] });
const f = t.mock.fn();
const timer = setTimeout(() => {
f();
// Clearing the already-expired timeout should do nothing.
// This call to clearTimeout removes the current timeout from the execution queue
clearTimeout(timer);
}, 50);
// Once the above callback runs, the call to `#executionQueue.shift()` removes this timeout from the queue
setTimeout(f, 50);
setTimeout(f, 50);
t.mock.timers.runAll();
assert.strictEqual(f.mock.callCount(), 3); // AssertionError 2 !== 3
});
Review requested:
- [ ] @nodejs/test_runner
Nice catch!
CI: https://ci.nodejs.org/job/node-test-pull-request/57084/
CI: https://ci.nodejs.org/job/node-test-pull-request/57174/
CI: https://ci.nodejs.org/job/node-test-pull-request/57175/
Landed in 17187dd2edfee0e02d1618d9611b435fd81225b2