Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock a constructor like new Date()

I have a method which depends on new Date to create a date object and then manipulates it. I'm testing that the manipulation works as expected, so I need to compare the returned date with expected date. In order to do that I need to make sure that new Date returns the same value in the test and in the method being tested. How can I do that?

Is there a way to actually mock the return value of a constructor function?

I could create a module that can be required with a function that provides a date object and can be mocked. But that seems like an unnecessary abstraction in my code.

an example function to be tested...

module.exports = {   sameTimeTomorrow: function(){     var dt = new Date();         dt.setDate(dt + 1);     return dt;   } }; 

how do I mock the return value of new Date()?

like image 976
Seth Feldkamp Avatar asked Feb 13 '15 16:02

Seth Feldkamp


People also ask

How do you mock a date object?

Mock Date object js const RealDate = Date; beforeEach(() => { global. Date. now = jest. fn(() => new Date('2019-04-22T10:20:30Z').

How do you test a new date in jest?

const getCurrentDate = () => new Date(); test('It should create new date', () => { jest . spyOn(global, 'Date') . mockImplementationOnce(() => new Date('2019-05-14T11:01:58.135Z')); expect(getCurrentDate()). toEqual(new Date('2019-05-14T11:01:58.135Z')); });

How do you mock a constructor in jest?

In order to mock a constructor function, the module factory must return a constructor function. In other words, the module factory must be a function that returns a function - a higher-order function (HOF). Since calls to jest. mock() are hoisted to the top of the file, Jest prevents access to out-of-scope variables.

Does new date () return a string?

Use new Date() to get a Date for the current time or Date. now() to get the current time in milliseconds since 01 January, 1970 UTC. Returns a string representation of the current date and time.


2 Answers

Since jest 26, you can use the 'modern' fakeTimers implementation (see article here) wich supports the method jest.setSystemTime.

beforeAll(() => {     jest.useFakeTimers('modern');     jest.setSystemTime(new Date(2020, 3, 1)); });  afterAll(() => {     jest.useRealTimers(); }); 

Note that 'modern' will be the default implementation from jest version 27.

See documentation for setSystemTime here.

like image 125
ThdK Avatar answered Oct 08 '22 12:10

ThdK


Update: this answer is the approach for jest < version 26 see this answer for recent jest versions.


You can mock a constructor like new Date() using jest.spyOn as below:

test('mocks a constructor like new Date()', () => {   console.log('Normal:   ', new Date().getTime())    const mockDate = new Date(1466424490000)   const spy = jest     .spyOn(global, 'Date')     .mockImplementation(() => mockDate)    console.log('Mocked:   ', new Date().getTime())   spy.mockRestore()    console.log('Restored: ', new Date().getTime()) }) 

And the output looks like:

Normal:    1566424897579 Mocked:    1466424490000 Restored:  1566424897608 

See the reference project on GitHub.

Note: If you are using TypeScript and you would encounter a compilation error, Argument of type '() => Date' is not assignable to parameter of type '() => string'. Type 'Date' is not assignable to type 'string'. In this case, a workaround is to use the mockdate library, which can be used to change when "now" is. See this question for more details.

like image 38
Yuci Avatar answered Oct 08 '22 12:10

Yuci