Add specs to test if issue #655 is present: the handler of an interval cannot successfully clear the same interval that generated it's invocation. The most direct test consist in setting an interval with a handler that calls clearInterval over that same interval and make the clock tick for double of it's period. If the issue is present the interval's handler will be called twice. If the issue is not present, the first invocation of the handler will avoid a second one (because of the clearInterval). Another test is included in order to check if recurring scheduled functions are rescheduled before being called. Doing this in the reverse order is the exact cause of the issue.
260 lines
7.0 KiB
JavaScript
260 lines
7.0 KiB
JavaScript
describe("DelayedFunctionScheduler", function() {
|
|
it("schedules a function for later execution", function() {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
fn = jasmine.createSpy('fn');
|
|
|
|
scheduler.scheduleFunction(fn, 0);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
|
|
scheduler.tick(0);
|
|
|
|
expect(fn).toHaveBeenCalled();
|
|
});
|
|
|
|
it("schedules a string for later execution", function() {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
strfn = "horrible = true;";
|
|
|
|
scheduler.scheduleFunction(strfn, 0);
|
|
|
|
scheduler.tick(0);
|
|
|
|
expect(horrible).toEqual(true);
|
|
});
|
|
|
|
it("#tick defaults to 0", function() {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
fn = jasmine.createSpy('fn');
|
|
|
|
scheduler.scheduleFunction(fn, 0);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
|
|
scheduler.tick();
|
|
|
|
expect(fn).toHaveBeenCalled();
|
|
});
|
|
|
|
it("defaults delay to 0", function() {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
fn = jasmine.createSpy('fn');
|
|
|
|
scheduler.scheduleFunction(fn);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
|
|
scheduler.tick(0);
|
|
|
|
expect(fn).toHaveBeenCalled();
|
|
});
|
|
|
|
it("optionally passes params to scheduled functions", function() {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
fn = jasmine.createSpy('fn');
|
|
|
|
scheduler.scheduleFunction(fn, 0, ['foo', 'bar']);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
|
|
scheduler.tick(0);
|
|
|
|
expect(fn).toHaveBeenCalledWith('foo', 'bar');
|
|
});
|
|
|
|
it("scheduled fns can optionally reoccur", function() {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
fn = jasmine.createSpy('fn');
|
|
|
|
scheduler.scheduleFunction(fn, 20, [], true);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
|
|
scheduler.tick(20);
|
|
|
|
expect(fn.calls.count()).toBe(1);
|
|
|
|
scheduler.tick(40);
|
|
|
|
expect(fn.calls.count()).toBe(3);
|
|
|
|
scheduler.tick(21);
|
|
|
|
expect(fn.calls.count()).toBe(4);
|
|
|
|
});
|
|
|
|
it("increments scheduled fns ids unless one is passed", function() {
|
|
var scheduler = new j$.DelayedFunctionScheduler();
|
|
|
|
expect(scheduler.scheduleFunction(function() {
|
|
}, 0)).toBe(1);
|
|
expect(scheduler.scheduleFunction(function() {
|
|
}, 0)).toBe(2);
|
|
expect(scheduler.scheduleFunction(function() {
|
|
}, 0, [], false, 123)).toBe(123);
|
|
expect(scheduler.scheduleFunction(function() {
|
|
}, 0)).toBe(3);
|
|
});
|
|
|
|
it("#removeFunctionWithId removes a previously scheduled function with a given id", function() {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
fn = jasmine.createSpy('fn'),
|
|
timeoutKey;
|
|
|
|
timeoutKey = scheduler.scheduleFunction(fn, 0);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
|
|
scheduler.removeFunctionWithId(timeoutKey);
|
|
|
|
scheduler.tick(0);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("reset removes scheduled functions", function() {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
fn = jasmine.createSpy('fn');
|
|
|
|
scheduler.scheduleFunction(fn, 0);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
|
|
scheduler.reset();
|
|
|
|
scheduler.tick(0);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("reset resets the returned ids", function() {
|
|
var scheduler = new j$.DelayedFunctionScheduler();
|
|
expect(scheduler.scheduleFunction(function() { }, 0)).toBe(1);
|
|
expect(scheduler.scheduleFunction(function() { }, 0, [], false, 123)).toBe(123);
|
|
|
|
scheduler.reset();
|
|
expect(scheduler.scheduleFunction(function() { }, 0)).toBe(1);
|
|
expect(scheduler.scheduleFunction(function() { }, 0, [], false, 123)).toBe(123);
|
|
});
|
|
|
|
it("reset resets the current tick time", function() {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
fn = jasmine.createSpy('fn');
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
|
|
scheduler.tick(15);
|
|
scheduler.reset();
|
|
|
|
scheduler.scheduleFunction(fn, 20, [], false, 1, 20);
|
|
|
|
scheduler.tick(5);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("executes recurring functions interleaved with regular functions in the correct order", function() {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
fn = jasmine.createSpy('fn'),
|
|
recurringCallCount = 0,
|
|
recurring = jasmine.createSpy('recurring').and.callFake(function() {
|
|
recurringCallCount++;
|
|
if (recurringCallCount < 5) {
|
|
expect(fn).not.toHaveBeenCalled();
|
|
}
|
|
});
|
|
|
|
scheduler.scheduleFunction(recurring, 10, [], true);
|
|
scheduler.scheduleFunction(fn, 50);
|
|
|
|
scheduler.tick(60);
|
|
|
|
expect(recurring).toHaveBeenCalled();
|
|
expect(recurring.calls.count()).toBe(6);
|
|
expect(fn).toHaveBeenCalled();
|
|
});
|
|
|
|
it("schedules a function for later execution during a tick", function () {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
fn = jasmine.createSpy('fn'),
|
|
fnDelay = 10;
|
|
|
|
scheduler.scheduleFunction(function () {
|
|
scheduler.scheduleFunction(fn, fnDelay);
|
|
}, 0);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
|
|
scheduler.tick(fnDelay);
|
|
|
|
expect(fn).toHaveBeenCalled();
|
|
});
|
|
|
|
it("#removeFunctionWithId removes a previously scheduled function with a given id during a tick", function () {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
fn = jasmine.createSpy('fn'),
|
|
fnDelay = 10,
|
|
timeoutKey;
|
|
|
|
scheduler.scheduleFunction(function () {
|
|
scheduler.removeFunctionWithId(timeoutKey);
|
|
}, 0);
|
|
timeoutKey = scheduler.scheduleFunction(fn, fnDelay);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
|
|
scheduler.tick(fnDelay);
|
|
|
|
expect(fn).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("executes recurring functions interleaved with regular functions and functions scheduled during a tick in the correct order", function () {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
fn = jasmine.createSpy('fn'),
|
|
recurringCallCount = 0,
|
|
recurring = jasmine.createSpy('recurring').and.callFake(function() {
|
|
recurringCallCount++;
|
|
if (recurringCallCount < 5) {
|
|
expect(fn).not.toHaveBeenCalled();
|
|
}
|
|
}),
|
|
innerFn = jasmine.createSpy('innerFn').and.callFake(function() {
|
|
expect(recurring.calls.count()).toBe(4);
|
|
expect(fn).not.toHaveBeenCalled();
|
|
}),
|
|
scheduling = jasmine.createSpy('scheduling').and.callFake(function() {
|
|
expect(recurring.calls.count()).toBe(3);
|
|
expect(fn).not.toHaveBeenCalled();
|
|
scheduler.scheduleFunction(innerFn, 10); // 41ms absolute
|
|
});
|
|
|
|
scheduler.scheduleFunction(recurring, 10, [], true);
|
|
scheduler.scheduleFunction(fn, 50);
|
|
scheduler.scheduleFunction(scheduling, 31);
|
|
|
|
scheduler.tick(60);
|
|
|
|
expect(recurring).toHaveBeenCalled();
|
|
expect(recurring.calls.count()).toBe(6);
|
|
expect(fn).toHaveBeenCalled();
|
|
expect(scheduling).toHaveBeenCalled();
|
|
expect(innerFn).toHaveBeenCalled();
|
|
});
|
|
|
|
it("executes recurring functions after rescheduling them", function () {
|
|
var scheduler = new j$.DelayedFunctionScheduler(),
|
|
recurring = function() {
|
|
expect(scheduler.scheduleFunction).toHaveBeenCalled();
|
|
};
|
|
|
|
scheduler.scheduleFunction(recurring, 10, [], true);
|
|
|
|
spyOn(scheduler, "scheduleFunction");
|
|
|
|
scheduler.tick(10);
|
|
});
|
|
|
|
});
|
|
|