I Am
Volodymyr Hudyma
<FrontEndDeveloper />
You Are Here: Home/How To Mock Date/Moment In Jest?

How To Mock Date/Moment In Jest?

October 31, 2020

Table Of Contents

    In most cases, you have to deal with date and time during project development.

    They can be components that display the current date, helper functions that calculate something based on the current date, and so on.

    Testing each of these cases with Jest can be a challenge, especially if you have not yet learned how to use it in tests.

    Today we will discuss this topic by means of some code examples.

    Example

    Let's create a component that displays the current date in Unix millisecond timestamp using the moment library:

    import React from "react";
    import moment from "moment";
    
    const App = () => (
      <div>Current unix milisecond timestamp: {moment().format("x")}</div>
    );
    
    export default App;

    The result of the rendering:

    Current date rendered

    So far it looks good. To be sure that the component does exactly what is expected, a proper test must be written:

    import React from "react";
    import { mount } from "enzyme";
    import moment from "moment";
    
    import App from "./App";
    
    it("renders current date", () => {
      const app = mount(<App />);
    
      const text = `Current unix milisecond timestamp: ${moment().format("x")}`;
    
      expect(app.text()).toContain(text);
    });

    Run the test and... notice that it fails with the following error message:

    Failing test

    It fails because it takes some time to execute the code after mounting the component and get the current timestamp with moment().format("x") function.

    It is obvious that writing tests that do not mock the current date to a static value is not reliable.

    Mock Date To Rescue

    Fortunately, there is a great library called mockdate, which serves exactly the purpose of mocking the current date in tests.

    Install the library:

    yarn add mockdate

    Refactor the test:

    import React from "react";
    import { mount } from "enzyme";
    import moment from "moment";
    import MockDate from "mockdate";
    
    import App from "./App";
    
    // Before all tests
    // Mock the current date
    beforeAll(() => {
      MockDate.set("2020-10-03");
    });
    
    it("renders current date", () => {
      const app = mount(<App />);
    
      const text = `Current unix milisecond timestamp: ${moment().format("x")}`;
    
      // Just for the testing purposes
      // Let's print rendered strings
      console.log("Component: ", app.text());
      console.log("Test: ", text);
    
      expect(app.text()).toContain(text);
    });

    And run it:

    Passing test

    Important note: Sometimes you have to mock the current date only for certain tests. This can be done by using the describe blocks and seting beforeAll and afterAll inside of them:

    describe("with mocked date", () => {
      // Mock the current date 
      // Only inside of this block
      beforeAll(() => {
        MockDate.set("2020-10-31");
      });
    
      // Reset the mock
      afterAll(() => {
        MockDate.reset();
      });
    
      it("renders current date", () => {
        const app = mount(<App />);
    
        const text = `Current unix milisecond timestamp: ${moment().format("x")}`;
    
        expect(app.text()).toContain(text);
      });
    });
    
    // Outside of the block the current date is not mocked

    Summary

    Proper dates handling is one of the most complex parts of JavaScript. There are several things developers should remember about when dealing with them.

    But one of the most important, apart from not forgetting to add tests for the produced code, is to use mocked date inside of them.

    Mockdate library offers a simple and reliable way to mock the current date in JavaScript.

    Newsletter
    Receive all new posts directly to your e-mail
    No spam, only quality content twice a week
    Let me know what you think about this article
    Click here to write response...