reactjsunit-testingjestjsmockingreact-testing-library

Jest setSystemTime not working with global scope


I am trying to tests a simple reducer which has a date property set to today.

const today = new Date();

export const initialState = {
  today
};

console.log(new Date().toDateString()); // <--- real date

export default function globalReducer(state = initialState, action) {
  console.log(new Date().toDateString()); // <--- mocked date
  switch (action.type) {
    default:
      return state;
  }
}

with my basic test

import globalReducer from "./reducer";

describe("Global reducer", () => {
  beforeAll(() => {
    jest.useFakeTimers("modern");
    jest.setSystemTime(new Date("2021-02-18"));
  });

  afterAll(() => {
    jest.useRealTimers();
  });

  it("should return the mocked date", () => {
    expect(globalReducer(undefined, {}).today).toEqual(new Date('2021-02-18'));
  });
});

What I noticed is that the mock only works inside the reducer code, but today in its global scope always returns the real date instead of the mocked one.

If I call the setSystemTime in the test setup file, then today is correctly mocked.

Am I missing something here? What would be the way of mocking a date in global scope only for a specific test?

A test repo is here if you want to check it out https://github.com/dariospadoni/jestFakeTimersMock


Solution

  • The reason for it to happen is because the Date is instantiated in recucer.js before setSystemTime is invoked.

    Here is an example how you can avoid that:

    beforeAll(() => {
      jest.setSystemTime(new Date("2021-02-18"));
    });
    
    describe("Global reducer", () => {
      let globalReducer;
    
      beforeAll(() => {
        globalReducer = require("./reducer").default;
      });
    
      it("should return the mocked date", () => {
        expect(globalReducer(undefined, {}).today).toEqual(new Date("2021-02-18"));
      });
    });
    

    Here the Date object will be instantiated once the reducer.js is required, and that would be after the setSystemTime is invoked