I have a directive that initializes the Date object several times in several functions. When Unit testing the individual functions I can handle stubbing the date like this:
angular.mock.TzDate would a better native alternative here. this comes as a helper from angular mocks and truly safe guard your test from the system timezone or any other dependencies
https://docs.angularjs.org/api/ngMock/type/angular.mock.TzDate
this plays well with Jasmine or mocha
I was able to mock using a combination of sinon's fake timers to mock the window's timers and angular's mock interval service for angular to recognize time changes . Here, the countDownService under test makes use internally of both javscript Date
and angular's normal interval service Something like:
describe('when start time was 3000 milliseconds and 1001 milliseconds have passed', function() {
var startTime;
var elapse;
beforeEach(function(){
this.clock = sinon.useFakeTimers();
startTime = 3000;
elapse = 1001;
});
var elapseMillis = function(intervalMock,sinonClock,millis){
sinonClock.tick(millis);
intervalMock.flush(millis);
};
it('elapsedMillis + timeRemainingMillis should == startime',
inject(function($rootScope,$interval,countdownService) {
countdownService.startTimer(startTime);
elapseMillis($interval,this.clock,elapse);
//jasmine clock does not mock Date
//see https://github.com/pivotal/jasmine/issues/361
var elapsedMillis = countdownService.getElapsedMillis();
var timeRemainingMillis = countdownService.getTimeRemainingMillis();
expect(elapsedMillis + timeRemainingMillis).toEqual(startTime);
expect(elapsedMillis).toEqual(elapse);
}));
afterEach(function(){
this.clock.restore();
startTime = 0;
elapse = 0;
});
});
You'll want to make sure and include sinon js's sinon-timers-1.8.1.js
in your karma.conf.js files property, too.
Jasmine (2.2) Clock can mock dates and time.
http://jasmine.github.io/2.2/introduction.html#section-Mocking_the_Date
For example (from the docs):
it("mocks the Date object and sets it to a given time", function() {
var baseTime = new Date(2013, 9, 23);
jasmine.clock().mockDate(baseTime);
jasmine.clock().tick(50);
expect(new Date().getTime()).toEqual(baseTime.getTime() + 50);
});
A straightforward solution would be to create an Angular Dates
service that provides Date
objects for you - it might even just have a single method - Dates.now()
- that just sends back the current date by returning new Date()
. You then use this service whenever something needs to get the current date.
This then allows you to inject a different Dates
service when unit testing, for example one that always returns a specific date of your choice when called, rather than the current time.