Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking dates in AngularJS / Jasmine tests

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:

(function (global) {
  var NativeDate = global.Date;

  global.stubDateConstructor = function (fakeDate) {
      global.Date = function () {
          global.Date = NativeDate;
          return fakeDate;
      }
  }
}(this));

// ageInYears()
it("should return the age in years of the person given his/her birthdate", function() {
    stubDateConstructor(new Date('2010/01/01'));
    expect(ageInYears('01-01-1990')).toBe(20);
    stubDateConstructor(new Date('2010/01/01'));
    expect(ageInYears('01-01-1900')).toBe(110);
});

For unittesting the directive itself, which calls the ageInYears and several other similar functions this isn't going to work as I after one call to Date() stubDateConstructor will have reset Date() to the real Date object.

Is there a native way in AngularJS / Jasmine to handle these situations, or should I look into Sinon e.g.?

like image 486
Maarten Avatar asked Jun 13 '13 11:06

Maarten


People also ask

How do you mock the current date in Jasmine?

it("should return decremented duration as time passes", () => { const timer = new Timer(5, true); jasmine. clock(). mockDate(new Date(startingTime + 1000)); expect(timer.

What is mocking in unit testing Angular?

Introduction. Mocking is a great idea for testing Angular apps because it makes maintenance easier and helps reduce future bugs. There are a few complex tools, such as XUnit, for mocking an Angular CLI project. You can execute the mocking methods described in this guide only if you use vanilla Jasmine + Angular Testbed ...


3 Answers

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);
});
like image 180
Rimian Avatar answered Oct 09 '22 18:10

Rimian


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.

like image 30
Dave Avatar answered Oct 09 '22 19:10

Dave


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

like image 1
prasanth shenoy Avatar answered Oct 09 '22 19:10

prasanth shenoy