From af5875c6e8117bdb4dce392696f073b9c6be2232 Mon Sep 17 00:00:00 2001 From: Ben Richeson <36977340+Benricheson101@users.noreply.github.com> Date: Sun, 18 Feb 2024 06:08:44 -0500 Subject: [PATCH] test_runner: check if timeout was cleared by own callback PR-URL: https://github.com/nodejs/node/pull/51673 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Marco Ippolito Reviewed-By: Moshe Atlow --- lib/internal/test_runner/mock/mock_timers.js | 8 ++++++-- test/parallel/test-runner-mock-timers.js | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/internal/test_runner/mock/mock_timers.js b/lib/internal/test_runner/mock/mock_timers.js index 85512cc4b66a51..00fe29d43c97ad 100644 --- a/lib/internal/test_runner/mock/mock_timers.js +++ b/lib/internal/test_runner/mock/mock_timers.js @@ -622,8 +622,12 @@ class MockTimers { if (timer.runAt > this.#now) break; FunctionPrototypeApply(timer.callback, undefined, timer.args); - this.#executionQueue.shift(); - timer.priorityQueuePosition = undefined; + // Check if the timeout was cleared by calling clearTimeout inside its own callback + const afterCallback = this.#executionQueue.peek(); + if (afterCallback.id === timer.id) { + this.#executionQueue.shift(); + timer.priorityQueuePosition = undefined; + } if (timer.interval !== undefined) { timer.runAt += timer.interval; diff --git a/test/parallel/test-runner-mock-timers.js b/test/parallel/test-runner-mock-timers.js index eb5cec84e122f2..7e519e8a2ad2fb 100644 --- a/test/parallel/test-runner-mock-timers.js +++ b/test/parallel/test-runner-mock-timers.js @@ -532,6 +532,22 @@ describe('Mock Timers Test Suite', () => { await nodeTimersPromises.setImmediate(); // let promises settle assert.strictEqual(f2.mock.callCount(), 1); }); + + it('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 = nodeTimers.setTimeout(() => { + f(); + // Clearing the already-expired timeout should do nothing + nodeTimers.clearTimeout(timer); + }, 50); + nodeTimers.setTimeout(f, 50); + nodeTimers.setTimeout(f, 50); + + t.mock.timers.runAll(); + assert.strictEqual(f.mock.callCount(), 3); + }); }); describe('setInterval Suite', () => {