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()?
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.
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.
You can use jasmine's spyOn (jest is built on jasmine) to mock Date's prototype for getDate as follows:
spyOn(Date.prototype, 'setDate').and.returnValue(DATE_TO_TEST_WITH);
SpyOn will also clean up after it's self and only lasts for the scope of the test.