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()
?
Solution 1:
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.
Solution 2:
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.