As the title says, I'm having some difficulty mocking a call to new Date() constructor in Jest. I'm mocking this call to ensure my tests do not fail, by returning a specific date time. However, as the date constructor is called twice in the function I'm testing, the second call also has its implementation mocked too, this second call should not be mocked.
I've provided an example below for context, it's a little function that returns the number of seconds until tomorrow, hence the requirement to mock a consistent now time.
Any assistance would be a great help, I've exhausted searches through Stack Overflow and the Jest docs.
Thanks in advance.
Function
function getSecondsToTomorrow() {
// This call needs to be mocked to always return the same date time
const now = new Date();
// This call should not be mocked
const tomorrow = new Date(
now.getFullYear(),
now.getMonth(),
now.getDate() + 1,
);
return Math.round( (tomorrow - now) / 1000);
}
Tests
describe("getSecondsToTomorrow()", () => {
let result, mockDate, now;
beforeAll(() => {
now = new Date(2020, 7, 3, 23, 0, 0);
mockDate = jest.spyOn(global, "Date").mockImplementation(() => now);
result = getSecondsToTomorrow();
});
afterAll(() => {
mockDate.mockRestore();
});
it("should return the number of seconds until tomorrow, from the time the function was called", () => {
// We mock the date to be 2300, so the return should be 1 hour (3600 seconds)
expect(result).toBe(3600);
});
});
Update
Although I still haven't found a specific answer to my question, I have found a workaround. Namely using Jest's mockImplementationOnce method, I can mock a datetime on the first call to new Date() and pass through any arguments on the second call as a default mockImplementation.
describe("getSecondsToTomorrow()", () => {
let result, mockDate, now, dateClone;
function setUpDateMock(now) {
return jest
.spyOn(global, "Date")
.mockImplementation((...args) => new dateClone(...args))
.mockImplementationOnce(() => now)
}
beforeAll(() => {
dateClone = Date;
now = new Date(2020, 7, 3, 23, 0, 0);
mockDate = setUpDateMock(now);
result = getSecondsToTomorrow();
});
afterAll(() => {
mockDate.mockRestore();
});
it("should return the number of seconds until tomorrow, from the time the function was called", () => {
expect(result).toBe(3600);
});
});