How to apply mock in "new date()" using Jest?

Asked

Viewed 470 times

5

Please someone knows how to apply mock in the new Date() using the Jest?

I tried to do so, but it did not work. The date remains current:

jest.spyOn(Date, 'now').mockImplementation(() => {
    return new Date(2020, 9, 1, 7).getTime();
})

console.log(new Date());
console.log(new Date(Date.now()));

Upshot:

console.log
  2020-10-30T16:16:44.122Z

console.log
  2020-10-01T10:00:00.000Z

There’s something I don’t know. Um ...

  • 1

    @Luizfelipe theDate.now() is working yes, but what I need is to "mock" the new Date(). It is without using the Date.now(). Got it?

2 answers

4

The Date is a global object in Javascript. This means that it is a property of window (in the browser), of global (in Node.js) or globalThis (in browsers modern and recent versions of Node.js).

Since Jest runs on Node.js, we can use global to access it. From Node.js 12.4.0 you can use globalThis also.

Thus, to mock Date, we must "spy" the object containing it. Thus:

const mockedDate = new Date(2000, 9, 1, 7);
jest.spyOn(global, 'Date').mockImplementation(() => {
  return mockedDate;
});

How you are using Typescript, in the specific case of mock of Date, will pass any as "argument" for the two generics of spyOn, since Jest’s type definitions have a certain conflict regarding the type of Date. That’s because Date can be applied (returning type string) or instantiated, returning type Date. Since both cases are possible, Typescript is not able to define which of the overloads will be used.

Therefore, as the definition of types would only take the first case into account (in the case, string), we have to do:

const mockedDate = new Date(2000, 9, 1, 7);
//        ↓↓↓↓↓↓↓↓↓↓
jest.spyOn<any, any>(global, 'Date').mockImplementation(() => {
  return mockedDate;
})

Now whenever you build a new date, you will have it mocked. Note that we had to instantiate the date to be returned by mock outside the callback of mockImplementation not to fall into a loop infinite.

If we give a console.log(new Date()) now we will have the following exit:

console.log
  2000-10-01T10:00:00.000Z
  • Thanks for your reply. I tried your code, but here on my PC it causes this problem when running the tests: bash&#xA;error TS2345: Argument of type '() => Date' is not assignable to parameter of type '() => string'.&#xA; Type 'Date' is not assignable to type 'string'.&#xA;&#xA; 28 jest.spyOn(global, 'Date').mockImplementation(() => {&#xA; ~~~~~~~&#xA; Hum ... will be why?

  • @Deividsondamasio, I edited the answer. :-)

  • 1

    Excuse me, I just put the tag javascript in the statement of the question and this caused some confusion. I will accept your answer because it was very enlightening, but I will post my answer here too.

4


The response of Luiz Felipe was very enlightening, so I accepted his reply.
But I’m posting here also my answer.

From Jest 26, this can be achieved using "modern "fake timers".

This was the best solution I could find on the gringo sites:

jest.useFakeTimers('modern').setSystemTime(new Date(2020, 9, 1, 7));

console.log(new Date());
console.log(new Date(Date.now()));

Upshot:

console.log
  2020-10-01T10:00:00.000Z

console.log
  2020-10-01T10:00:00.000Z

References:
https://jestjs.io/blog/2020/05/05/jest-26#new-fake-timers
(Accessed 30 October 2020)

https://github.com/sinonjs/fake-timers/blob/master/README.md#clocksetsystemtimenow
(Accessed 30 October 2020)

  • Excellent. I didn’t know about them; I even suggest you accept this answer instead of mine (which is undoubtedly more useful for mock date). :-)

  • 1

    All right then. Since you asked. But Stack Overflow message: "You can accept your own answer in 2 days."

  • I found this very good... it became much simpler and from what I read, it is for this function. (ref.: https://testing-library.com/docs/using-fake-timers/)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.