From 84daa0f5dc443d689293b46ddd813fc6aa6777ab Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Wed, 30 Apr 2025 13:33:54 -0700 Subject: [PATCH 1/2] fix(Clock): Ensure that uninstalling the clock also stops auto tick The autotick feature mistakenly does not account for the clock being a singleton and the re-installation of the clock causes the auto ticking exit conditions to become true again, before it has a chance to break. --- spec/core/ClockSpec.js | 20 ++++++++++++++++++++ src/core/Clock.js | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/spec/core/ClockSpec.js b/spec/core/ClockSpec.js index dbdbbfd6..3eba9032 100644 --- a/spec/core/ClockSpec.js +++ b/spec/core/ClockSpec.js @@ -776,6 +776,26 @@ describe('Clock (acceptance)', function() { }); }); + it('aborts auto ticking when uninstalled, even if installed again synchonrously', async () => { + clock.uninstall(); + clock.install(); + + let resolved = false; + const promise = new Promise(resolve => { + clock.setTimeout(resolve, 1); + }).then(() => { + resolved = true; + }); + + // wait some real time and verify that the clock did not flush the timer above automatically + await new Promise(resolve => setTimeout(resolve, 2)); + expect(resolved).toBe(false); + + // enabling auto tick again will flush the timer + clock.autoTick(); + await expectAsync(promise).toBeResolved(); + }); + it('speeds up the execution of the timers in all browsers', async () => { const startTimeMs = performance.now() / 1000; await new Promise(resolve => clock.setTimeout(resolve, 5000)); diff --git a/src/core/Clock.js b/src/core/Clock.js index dc2378d6..f610c551 100644 --- a/src/core/Clock.js +++ b/src/core/Clock.js @@ -69,6 +69,10 @@ getJasmineRequireObj().Clock = function() { * @function */ this.uninstall = function() { + // Ensure auto ticking loop is aborted when clock is uninstalled + if (tickMode.mode === 'auto') { + tickMode = { mode: 'manual', counter: tickMode.counter + 1 }; + } delayedFunctionScheduler = null; mockDate.uninstall(); replace(global, realTimingFunctions); From 3ecddc2555d248c2bb7634114a3c1c49fac15137 Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Thu, 1 May 2025 10:25:24 -0700 Subject: [PATCH 2/2] fixup! fix(Clock): Ensure that uninstalling the clock also stops auto tick --- spec/core/ClockSpec.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/spec/core/ClockSpec.js b/spec/core/ClockSpec.js index 3eba9032..83b60570 100644 --- a/spec/core/ClockSpec.js +++ b/spec/core/ClockSpec.js @@ -699,16 +699,19 @@ describe('Clock (acceptance)', function() { tick: function() {}, uninstall: function() {} }; + // window setTimeout to window to make firefox happy + const _setTimeout = + typeof window !== 'undefined' ? setTimeout.bind(window) : setTimeout; + // passing a fake global allows us to preserve the real timing functions for use in tests + const _global = { setTimeout: _setTimeout, setInterval: setInterval }; clock = new jasmineUnderTest.Clock( - // We use the real window for global or firefox is displeased when we try to call a real setTimeout on an object "that doesn't implement window". - typeof window !== 'undefined' ? window : { setTimeout: setTimeout }, + _global, function() { return delayedFunctionScheduler; }, mockDate ); - clock.install(); - clock.autoTick(); + clock.install().autoTick(); }); afterEach(() => {