diff --git a/lib/jasmine-core/jasmine.js b/lib/jasmine-core/jasmine.js index f0f9deeb..8c01be21 100644 --- a/lib/jasmine-core/jasmine.js +++ b/lib/jasmine-core/jasmine.js @@ -3565,7 +3565,6 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { var endTime = currentTime + millis; runScheduledFunctions(endTime, tickDate); - currentTime = endTime; }; self.scheduleFunction = function( @@ -3683,16 +3682,20 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { function runScheduledFunctions(endTime, tickDate) { tickDate = tickDate || function() {}; if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) { - tickDate(endTime - currentTime); + if (endTime >= currentTime) { + tickDate(endTime - currentTime); + currentTime = endTime; + } return; } do { deletedKeys = []; var newCurrentTime = scheduledLookup.shift(); - tickDate(newCurrentTime - currentTime); - - currentTime = newCurrentTime; + if (newCurrentTime >= currentTime) { + tickDate(newCurrentTime - currentTime); + currentTime = newCurrentTime; + } var funcsToRun = scheduledFunctions[currentTime]; @@ -3721,8 +3724,9 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { ); // ran out of functions to call, but still time left on the clock - if (currentTime !== endTime) { + if (endTime >= currentTime) { tickDate(endTime - currentTime); + currentTime = endTime; } } } diff --git a/spec/core/DelayedFunctionSchedulerSpec.js b/spec/core/DelayedFunctionSchedulerSpec.js index d06a66c1..f5879e13 100644 --- a/spec/core/DelayedFunctionSchedulerSpec.js +++ b/spec/core/DelayedFunctionSchedulerSpec.js @@ -278,4 +278,58 @@ describe('DelayedFunctionScheduler', function() { expect(tickDate).toHaveBeenCalledWith(0); expect(tickDate).toHaveBeenCalledWith(1); }); + + describe('ticking inside a scheduled function', function() { + let clock; + + // Runner function calls the callback until it returns false + function runWork(workCallback) { + while (workCallback()) {} + } + + // Make a worker that takes a little time and tracks when it finished + function mockWork(times) { + return () => { + clock.tick(1); + const now = new Date().getTime(); + expect(lastWork) + .withContext('Previous function calls should always be in the past') + .toBeLessThan(now); + lastWork = now; + times--; + return times > 0; + }; + } + let lastWork = 0; + + beforeEach(() => { + clock = jasmine.clock(); + clock.install(); + clock.mockDate(new Date(1)); + }); + + afterEach(function() { + jasmine.clock().uninstall(); + }); + + it('preserves monotonically-increasing current time', () => { + const work1 = mockWork(3); + setTimeout(() => { + runWork(work1); + }, 1); + clock.tick(1); + expect(lastWork) + .withContext('tick should advance past last-scheduled function') + .toBeLessThanOrEqual(new Date().getTime()); + + const work2 = mockWork(3); + setTimeout(() => { + runWork(work2); + }, 1); + clock.tick(1); + expect(lastWork) + .withContext('tick should advance past last-scheduled function') + .toBeLessThanOrEqual(new Date().getTime()); + }); + }); }); diff --git a/src/core/DelayedFunctionScheduler.js b/src/core/DelayedFunctionScheduler.js index eb84c48a..aabdd911 100644 --- a/src/core/DelayedFunctionScheduler.js +++ b/src/core/DelayedFunctionScheduler.js @@ -12,7 +12,6 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { var endTime = currentTime + millis; runScheduledFunctions(endTime, tickDate); - currentTime = endTime; }; self.scheduleFunction = function( @@ -130,16 +129,20 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { function runScheduledFunctions(endTime, tickDate) { tickDate = tickDate || function() {}; if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) { - tickDate(endTime - currentTime); + if (endTime >= currentTime) { + tickDate(endTime - currentTime); + currentTime = endTime; + } return; } do { deletedKeys = []; var newCurrentTime = scheduledLookup.shift(); - tickDate(newCurrentTime - currentTime); - - currentTime = newCurrentTime; + if (newCurrentTime >= currentTime) { + tickDate(newCurrentTime - currentTime); + currentTime = newCurrentTime; + } var funcsToRun = scheduledFunctions[currentTime]; @@ -168,8 +171,9 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) { ); // ran out of functions to call, but still time left on the clock - if (currentTime !== endTime) { + if (endTime >= currentTime) { tickDate(endTime - currentTime); + currentTime = endTime; } } }