From 7b19708dec3249df891ad0b5edff43c5d4009043 Mon Sep 17 00:00:00 2001 From: hotpineapple Date: Fri, 15 Aug 2025 15:11:50 +0900 Subject: [PATCH] test_runner: set mock timer's interval undefined prevent adding timer to execution queue if clearInterval() called --- lib/internal/test_runner/mock/mock_timers.js | 1 + test/parallel/test-runner-mock-timers.js | 21 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/internal/test_runner/mock/mock_timers.js b/lib/internal/test_runner/mock/mock_timers.js index f955bea8089deb..490f8cd06fc549 100644 --- a/lib/internal/test_runner/mock/mock_timers.js +++ b/lib/internal/test_runner/mock/mock_timers.js @@ -321,6 +321,7 @@ class MockTimers { if (timer?.priorityQueuePosition !== undefined) { this.#executionQueue.removeAt(timer.priorityQueuePosition); timer.priorityQueuePosition = undefined; + timer.interval = undefined; } } diff --git a/test/parallel/test-runner-mock-timers.js b/test/parallel/test-runner-mock-timers.js index 722c2b362d61e1..f99936f449bc77 100644 --- a/test/parallel/test-runner-mock-timers.js +++ b/test/parallel/test-runner-mock-timers.js @@ -201,6 +201,27 @@ describe('Mock Timers Test Suite', () => { // Should not throw }); }); + + it('interval cleared inside callback should only fire once', (t) => { + t.mock.timers.enable(); + const calls = []; + + setInterval(() => { + calls.push('foo'); + }, 10); + const timerId = setInterval(() => { + calls.push('bar'); + clearInterval(timerId); + }, 10); + + t.mock.timers.tick(10); + t.mock.timers.tick(10); + + assert.deepStrictEqual( + calls, + ['foo', 'bar', 'foo'], + ); + }); }); describe('globals/timers', () => {