While writing tests for an Angular app, one scenario required a page to behave differently depending on whether the time of day was before or after 6 AM. The logic was simple enough to include in the controller:
vm.date = moment().subtract(6, 'hours').toDate();
The intended behavior: if the time is before 6 AM, display the previous day; otherwise, display today. However, the challenge in testing this controller was controlling the current time to evaluate both outcomes.
Sinon.js (http://sinonjs.org/) is a commonly used library for mocking dependencies in Angular tests. One of its features, useFakeTimers, is especially useful for handling time-dependent scenarios. With useFakeTimers, the time within a test can be set to any value. The following demonstrates how to simulate a page load before 6 AM:
clock = sinon.useFakeTimers(new Date(2016,2,15).getTime()); //sets date to Mar 15, 2016, at 00:00
clock.tick(60*60*2*1000); //move the fake time ahead to 2AM
By passing in a specific date to useFakeTimers, tests can define any starting point. The clock.tick() function allows precise manipulation of the time.
Pro Tip: Remember to call clock.restore() to reset the date/time in the afterEach function of your specs.
Putting it all together
The useFakeTimers feature in sinon.js made this a straightforward scenario to test.
'use strict';
describe('time specs', function() {
var scope, controller;
var clock, moment;
beforeEach(module('app'));
beforeEach(inject(function($rootScope, $controller, _moment_) {
scope = $rootScope.$new();
moment = _moment_;
}));
describe('when the page loads', function() {
describe('and it is earlier than 6AM', function() {
beforeEach(inject(function($controller) {
clock = sinon.useFakeTimers(new Date(2016, 2, 15).getTime()); // sets date to Mar 15, 2016 at 00:00
clock.tick(60 * 60 * 2 * 1000); // move the fake time ahead to 2AM
controller = $controller('PageController', {
$scope: scope
});
scope.vm = controller;
}));
it('then the date should default to yesterday', function() {
expect(moment(scope.vm.date).format('MM-DD-YYYY')).to.be.equal(moment().subtract(1, 'day').format('MM-DD-YYYY'));
});
});
describe('and it is later than 6AM', function() {
beforeEach(inject(function($controller) {
clock = sinon.useFakeTimers(new Date(2016, 2, 5).getTime()); // sets date to Mar 5, 2016 at 00:00
clock.tick(60 * 60 * 9 * 1000); // move the fake time ahead to 9AM
controller = $controller('PageController', {
$scope: scope
});
scope.vm = controller;
}));
it('then the date should default to today', function() {
expect(moment(scope.vm.date).format('MM-DD-YYYY')).to.be.equal(moment().format('MM-DD-YYYY'));
});
});
});
afterEach(function() {
clock.restore();
});
});
Looking for a new job? We work with some of the biggest names in tech, and we’re hiring! Check out our open jobs and make your next career move with Planet.