Support browsers that don't supply a Date.now()

- install the mockDate by calling `mockDate` on `clock` instead of
  passing an argument to `clock.install()`

[Finishes #66606132] Closes #361
This commit is contained in:
Elana Koren and Gregg Van Hove
2014-02-27 11:55:25 -08:00
parent 627a262085
commit eebba2ecca
4 changed files with 158 additions and 99 deletions

View File

@@ -5,7 +5,8 @@ describe("Clock", function() {
fakeGlobal = { setTimeout: fakeSetTimeout },
delayedFunctionScheduler = jasmine.createSpyObj("delayedFunctionScheduler", ["scheduleFunction"]),
delayedFn = jasmine.createSpy("delayedFn"),
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
fakeGlobal.setTimeout(delayedFn, 0);
@@ -26,7 +27,8 @@ describe("Clock", function() {
fakeGlobal = { clearTimeout: fakeClearTimeout },
delayedFunctionScheduler = jasmine.createSpyObj("delayedFunctionScheduler", ["removeFunctionWithId"]),
delayedFn = jasmine.createSpy("delayedFn"),
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
fakeGlobal.clearTimeout("foo");
@@ -47,7 +49,8 @@ describe("Clock", function() {
fakeGlobal = { setInterval: fakeSetInterval },
delayedFunctionScheduler = jasmine.createSpyObj("delayedFunctionScheduler", ["scheduleFunction"]),
delayedFn = jasmine.createSpy("delayedFn"),
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
fakeGlobal.setInterval(delayedFn, 0);
@@ -68,7 +71,8 @@ describe("Clock", function() {
fakeGlobal = { clearInterval: fakeClearInterval },
delayedFunctionScheduler = jasmine.createSpyObj("delayedFunctionScheduler", ["removeFunctionWithId"]),
delayedFn = jasmine.createSpy("delayedFn"),
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
fakeGlobal.clearInterval("foo");
@@ -97,7 +101,8 @@ describe("Clock", function() {
},
delayedFunctionScheduler = jasmine.createSpyObj("delayedFunctionScheduler", ["scheduleFunction", "reset"]),
delayedFn = jasmine.createSpy("delayedFn"),
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
clock.install();
clock.uninstall();
@@ -119,7 +124,8 @@ describe("Clock", function() {
delayedFunctionScheduler = { scheduleFunction: scheduleFunction },
fakeGlobal = { setTimeout: fakeSetTimeout },
delayedFn = jasmine.createSpy('delayedFn'),
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
clock.install();
clock.setTimeout(delayedFn, 0, 'a', 'b');
@@ -135,7 +141,8 @@ describe("Clock", function() {
delayedFunctionScheduler = {scheduleFunction: scheduleFunction},
fakeGlobal = { setTimeout: fakeSetTimeout },
delayedFn = jasmine.createSpy('delayedFn'),
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler),
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate),
timeoutId;
clock.install();
@@ -149,7 +156,8 @@ describe("Clock", function() {
delayedFunctionScheduler = jasmine.createSpyObj('delayedFunctionScheduler', ['removeFunctionWithId']),
fakeGlobal = { setTimeout: fakeClearTimeout },
delayedFn = jasmine.createSpy('delayedFn'),
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
clock.install();
clock.clearTimeout(123);
@@ -164,7 +172,8 @@ describe("Clock", function() {
delayedFunctionScheduler = {scheduleFunction: scheduleFunction},
fakeGlobal = { setInterval: fakeSetInterval },
delayedFn = jasmine.createSpy('delayedFn'),
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
clock.install();
clock.setInterval(delayedFn, 0, 'a', 'b');
@@ -180,7 +189,8 @@ describe("Clock", function() {
delayedFunctionScheduler = {scheduleFunction: scheduleFunction},
fakeGlobal = { setInterval: fakeSetInterval },
delayedFn = jasmine.createSpy('delayedFn'),
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler),
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate),
intervalId;
clock.install();
@@ -194,7 +204,8 @@ describe("Clock", function() {
delayedFunctionScheduler = jasmine.createSpyObj('delayedFunctionScheduler', ['removeFunctionWithId']),
fakeGlobal = { setInterval: clearInterval },
delayedFn = jasmine.createSpy('delayedFn'),
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
clock.install();
clock.clearInterval(123);
@@ -220,7 +231,8 @@ describe("Clock", function() {
setTimeout: fakeSetTimeout,
setInterval: fakeSetInterval
},
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock(fakeGlobal, delayedFunctionScheduler, mockDate);
fakeSetTimeout.apply = null;
fakeSetInterval.apply = null;
@@ -249,7 +261,8 @@ describe("Clock (acceptance)", function() {
delayedFn3 = jasmine.createSpy('delayedFn3'),
recurring1 = jasmine.createSpy('recurring1'),
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
clock = new j$.Clock({setTimeout: setTimeout}, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock({setTimeout: setTimeout}, delayedFunctionScheduler, mockDate);
clock.install();
@@ -295,7 +308,8 @@ describe("Clock (acceptance)", function() {
it("can clear a previously set timeout", function() {
var clearedFn = jasmine.createSpy('clearedFn'),
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler),
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler, mockDate),
timeoutId;
clock.install();
@@ -312,7 +326,8 @@ describe("Clock (acceptance)", function() {
it("correctly schedules functions after the Clock has advanced", function() {
var delayedFn1 = jasmine.createSpy('delayedFn1'),
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler, mockDate);
clock.install();
@@ -328,7 +343,8 @@ describe("Clock (acceptance)", function() {
var delayedFn1 = jasmine.createSpy('delayedFn1'),
delayedFn2 = jasmine.createSpy('delayedFn2'),
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler, mockDate);
delayedFn1.and.callFake(function() { clock.setTimeout(delayedFn2, 0); });
clock.install();
@@ -346,7 +362,8 @@ describe("Clock (acceptance)", function() {
var delayedFn1 = jasmine.createSpy('delayedFn1'),
delayedFn2 = jasmine.createSpy('delayedFn2'),
delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler);
mockDate = { install: function() {}, tick: function() {}, uninstall: function() {} },
clock = new j$.Clock({setTimeout: function() {}}, delayedFunctionScheduler, mockDate);
delayedFn1.and.callFake(function() { clock.setTimeout(delayedFn2, 1); });
clock.install();
@@ -357,7 +374,7 @@ describe("Clock (acceptance)", function() {
expect(delayedFn2).toHaveBeenCalled();
});
it("does not mock the Date object when installing without parameters", function() {
it("does not mock the Date object by default", function() {
var delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
global = {Date: Date},
mockDate = new j$.MockDate(global),
@@ -367,30 +384,30 @@ describe("Clock (acceptance)", function() {
expect(global.Date).toEqual(Date);
var now = global.Date.now();
var now = new global.Date().getTime();
clock.tick(50);
expect(global.Date.now() - now).not.toEqual(50);
expect(new global.Date().getTime() - now).not.toEqual(50);
});
it("mocks the Date object and sets it to current time when installing with true parameter", function() {
it("mocks the Date object and sets it to current time", function() {
var delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
global = {Date: Date},
mockDate = new j$.MockDate(global),
clock = new j$.Clock({setTimeout: setTimeout}, delayedFunctionScheduler, mockDate);
clock.install(true);
clock.install().mockDate();
var now = global.Date.now();
var now = new global.Date().getTime();
clock.tick(50);
expect(global.Date.now() - now).toEqual(50);
expect(new global.Date().getTime() - now).toEqual(50);
var timeoutDate = 0;
clock.setTimeout(function() {
timeoutDate = global.Date.now();
timeoutDate = new global.Date().getTime();
}, 100);
clock.tick(100);
@@ -398,7 +415,7 @@ describe("Clock (acceptance)", function() {
expect(timeoutDate - now).toEqual(150);
});
it("mocks the Date object and sets it to a given time when installing with a Date parameter", function() {
it("mocks the Date object and sets it to a given time", function() {
var delayedFunctionScheduler = new j$.DelayedFunctionScheduler(),
global = {Date: Date},
mockDate = new j$.MockDate(global),
@@ -406,19 +423,19 @@ describe("Clock (acceptance)", function() {
baseTime = new Date(2013, 9, 23);
clock.install(baseTime);
clock.install().mockDate(baseTime);
var now = global.Date.now();
var now = new global.Date().getTime();
expect(now).toEqual(baseTime.getTime());
clock.tick(50);
expect(global.Date.now()).toEqual(baseTime.getTime() + 50);
expect(new global.Date().getTime()).toEqual(baseTime.getTime() + 50);
var timeoutDate = 0;
clock.setTimeout(function() {
timeoutDate = global.Date.now();
timeoutDate = new global.Date().getTime();
}, 100);
clock.tick(100);

View File

@@ -3,84 +3,126 @@ describe("FakeDate", function() {
var fakeGlobal = {},
mockDate = new j$.MockDate(fakeGlobal);
mockDate.install();
fakeGlobal.Date = jasmine.createSpy("Date");
mockDate.tick(0);
expect(fakeGlobal.Date).not.toHaveBeenCalled();
expect(function() {
mockDate.install();
mockDate.tick(0);
mockDate.uninstall();
}).not.toThrow();
});
it("does not replace global Date if it is not installed", function() {
var fakeDate = jasmine.createSpy("global Date"),
fakeGlobal = { Date: fakeDate },
it("replaces the global Date when it is installed", function() {
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
return {
getTime: function() {}
}
}),
fakeGlobal = { Date: globalDate },
mockDate = new j$.MockDate(fakeGlobal);
fakeDate.now = function(){};
expect(fakeDate).toEqual(fakeGlobal.Date);
expect(fakeGlobal.Date).toEqual(globalDate);
mockDate.install();
expect(fakeDate).not.toEqual(fakeGlobal.Date);
expect(fakeGlobal.Date).not.toEqual(globalDate);
});
it("replaces the global Date on uninstall", function() {
var fakeDate = jasmine.createSpy("global Date"),
fakeGlobal = { Date: fakeDate },
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
return {
getTime: function() {}
}
}),
fakeGlobal = { Date: globalDate },
mockDate = new j$.MockDate(fakeGlobal);
fakeDate.now = function(){};
mockDate.install();
mockDate.uninstall();
expect(fakeDate).toEqual(fakeGlobal.Date);
expect(fakeGlobal.Date).toEqual(globalDate);
});
it("takes the current time as the base when installing without parameters", function() {
var fakeDate = jasmine.createSpy("global Date"),
fakeGlobal = { Date: fakeDate },
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
return {
getTime: function() {
return 1000;
}
}
}),
fakeGlobal = { Date: globalDate },
mockDate = new j$.MockDate(fakeGlobal);
fakeGlobal.Date.prototype.getTime = function() {
return 1000;
};
fakeDate.now = function(){ return 1000; };
mockDate.install();
expect(new fakeGlobal.Date().getTime()).toEqual(1000);
globalDate.calls.reset();
new fakeGlobal.Date();
expect(globalDate).toHaveBeenCalledWith(1000);
});
it("can accept a date as time base when installing", function() {
var fakeGlobal = { Date: Date },
mockDate = new j$.MockDate(fakeGlobal),
baseDate = new Date(2013, 9, 23);
baseDate = new Date();
spyOn(baseDate, 'getTime').and.returnValue(123);
mockDate.install(baseDate);
expect(new fakeGlobal.Date().getTime()).toEqual(baseDate.getTime());
expect(new fakeGlobal.Date().getTime()).toEqual(123);
});
it("makes real dates", function() {
var fakeGlobal = { Date: Date },
mockDate = new j$.MockDate(fakeGlobal);
mockDate.install();
expect(new fakeGlobal.Date()).toEqual(jasmine.any(Date));
});
it("fakes current time when using Date.now()", function() {
var fakeGlobal = { Date: Date },
mockDate = new j$.MockDate(fakeGlobal),
baseDate = new Date(2013, 9, 23);
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
return {
getTime: function() {
return 1000;
}
}
}),
fakeGlobal = { Date: globalDate };
mockDate.install(baseDate);
globalDate.now = function() {};
var mockDate = new j$.MockDate(fakeGlobal);
expect(fakeGlobal.Date.now()).toEqual(baseDate.getTime());
mockDate.install();
expect(fakeGlobal.Date.now()).toEqual(1000);
});
it("does not stub Date.now() if it doesn't already exist", function() {
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
return {
getTime: function() {
return 1000;
}
}
}),
fakeGlobal = { Date: globalDate },
mockDate = new j$.MockDate(fakeGlobal);
mockDate.install();
expect(fakeGlobal.Date.now).toThrowError("Browser does not support Date.now()");
});
it("makes time passes using tick", function() {
var fakeDate = jasmine.createSpy("global Date"),
fakeGlobal = { Date: fakeDate },
mockDate = new j$.MockDate(fakeGlobal);
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
return {
getTime: function() {
return 1000;
}
}
}),
fakeGlobal = { Date: globalDate };
fakeDate.now = function(){ return 1000; };
globalDate.now = function() {};
var mockDate = new j$.MockDate(fakeGlobal);
mockDate.install();
@@ -94,11 +136,17 @@ describe("FakeDate", function() {
});
it("allows to increase 0 milliseconds using tick", function() {
var fakeDate = jasmine.createSpy("global Date"),
fakeGlobal = { Date: fakeDate },
mockDate = new j$.MockDate(fakeGlobal);
var globalDate = jasmine.createSpy("global Date").and.callFake(function() {
return {
getTime: function() {
return 1000;
}
}
}),
fakeGlobal = { Date: globalDate };
fakeDate.now = function(){ return 1000; };
globalDate.now = function() {};
var mockDate = new j$.MockDate(fakeGlobal);
mockDate.install();
@@ -109,7 +157,7 @@ describe("FakeDate", function() {
expect(fakeGlobal.Date.now()).toEqual(1000);
});
it("allows to create a Date in a different time than now", function() {
it("allows to create a Date in a different time than the mocked time", function() {
var fakeGlobal = { Date: Date },
mockDate = new j$.MockDate(fakeGlobal),
baseDate = new Date(2013, 9, 23, 0, 0, 0, 0);
@@ -117,22 +165,14 @@ describe("FakeDate", function() {
mockDate.install(baseDate);
var otherDate = new fakeGlobal.Date(2013, 9, 23, 0, 0, 1, 0);
mockDate.tick(1000);
expect(fakeGlobal.Date.now()).toEqual(otherDate.getTime());
expect(otherDate.getTime()).not.toEqual(baseDate.getTime());
});
it("copies all Date properties to the mocked date", function() {
var fakeGlobal = { Date: Date },
mockDate = new j$.MockDate(fakeGlobal),
baseDate = new Date(2013, 9, 23, 0, 0, 0, 0);
mockDate = new j$.MockDate(fakeGlobal);
mockDate.install(baseDate);
var otherDate = new fakeGlobal.Date();
expect(otherDate).toEqual(jasmine.any(Date));
mockDate.install();
expect(fakeGlobal.Date.UTC(2013, 9, 23)).toEqual(Date.UTC(2013, 9, 23));
});

View File

@@ -1,5 +1,5 @@
getJasmineRequireObj().Clock = function() {
function Clock(global, delayedFunctionScheduler, date) {
function Clock(global, delayedFunctionScheduler, mockDate) {
var self = this,
realTimingFunctions = {
setTimeout: global.setTimeout,
@@ -17,27 +17,27 @@ getJasmineRequireObj().Clock = function() {
timer;
self.install = function(mockDate) {
self.install = function() {
replace(global, fakeTimingFunctions);
timer = fakeTimingFunctions;
installed = true;
if (date && mockDate) {
date.install(mockDate);
}
return self;
};
self.uninstall = function() {
delayedFunctionScheduler.reset();
if (date) {
date.uninstall();
}
mockDate.uninstall();
replace(global, realTimingFunctions);
timer = realTimingFunctions;
installed = false;
};
self.mockDate = function(initialDate) {
mockDate.install(initialDate);
};
self.setTimeout = function(fn, delay, params) {
if (legacyIE()) {
if (arguments.length > 2) {
@@ -68,9 +68,7 @@ getJasmineRequireObj().Clock = function() {
self.tick = function(millis) {
if (installed) {
if (date) {
date.tick(millis);
}
mockDate.tick(millis);
delayedFunctionScheduler.tick(millis);
} else {
throw new Error('Mock clock is not installed, use jasmine.clock().install()');

View File

@@ -13,10 +13,10 @@ getJasmineRequireObj().MockDate = function() {
var GlobalDate = global.Date;
self.install = function(mockDate) {
if (mockDate instanceof Date) {
if (mockDate instanceof GlobalDate) {
currentTime = mockDate.getTime();
} else {
currentTime = GlobalDate.now();
currentTime = new GlobalDate().getTime();
}
global.Date = FakeDate;
@@ -48,7 +48,11 @@ getJasmineRequireObj().MockDate = function() {
function createDateProperties() {
FakeDate.now = function() {
return currentTime;
if (GlobalDate.now) {
return currentTime;
} else {
throw new Error("Browser does not support Date.now()");
}
};
FakeDate.toSource = GlobalDate.toSource;