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("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); }); it("removes functions during a tick that runs the function", function() { var scheduler = new j$.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'), fnDelay = 10, timeoutKey; timeoutKey = scheduler.scheduleFunction(fn, fnDelay, [], true); scheduler.scheduleFunction(function () { scheduler.removeFunctionWithId(timeoutKey); }, 2 * fnDelay); expect(fn).not.toHaveBeenCalled(); scheduler.tick(3 * fnDelay); expect(fn).toHaveBeenCalled(); expect(fn.calls.count()).toBe(2); }); it("removes functions during the first tick that runs the function", function() { var scheduler = new j$.DelayedFunctionScheduler(), fn = jasmine.createSpy('fn'), fnDelay = 10, timeoutKey; timeoutKey = scheduler.scheduleFunction(fn, fnDelay, [], true); scheduler.scheduleFunction(function () { scheduler.removeFunctionWithId(timeoutKey); }, fnDelay); expect(fn).not.toHaveBeenCalled(); scheduler.tick(3 * fnDelay); expect(fn).toHaveBeenCalled(); expect(fn.calls.count()).toBe(1); }); });