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.
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:
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:
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.
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:
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
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.