Henrique Couto

Frontend software engineer

profile picture

Unit tests in Next with Jest

Unit testing is essential to ensure that our future maintenances will keep the components working.

Installing dependencies

To setup Jest we need to install the following packages jest, @testing-library/react and @testing-library/jest-dom:

1yarn add -D jest @testing-library/react @testing-library/jest-dom

Setting up tests

A setup file is needed for jest to run the tests.

Create a file jest.config.js in your project root folder:

1const nextJest = require("next/jest");
2
3const createJestConfig = nextJest({
4  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
5  dir: "./",
6});
7
8// Add any custom config to be passed to Jest
9const customJestConfig = {
10  // Add more setup options before each test is run
11  // setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
12  // if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
13  moduleDirectories: ["node_modules", "<rootDir>/"],
14  testEnvironment: "jest-environment-jsdom",
15};
16
17// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
18module.exports = createJestConfig(customJestConfig);

Now, create the script to run your tests in the package.json file:

1{
2 ...
3 "scripts": {
4    ...
5    "test": "jest --watch"
6  },
7 ...
8}

Creating our tests

In this example, let's to create the first test for GetInTouch component (from the main page of this blog).

The component has a title and some buttons that make a redirect for my profile in another sites. Let's test if the title appears correctly.

First, it is necessary to mock the internationalization hook, responsible for translating the blog texts.

1import { useIntl } from "../../hooks/useIntl";
2
3const TITLE = "GET IN TOUCH";
4jest.mock("../../hooks/useIntl");
5
6describe("Get In Touch Component", () => {
7  beforeAll(() => {
8    (useIntl as jest.Mock).mockImplementation(() => ({
9      getInTouch: { title: TITLE },
10    }));
11  });
12});

To test if the TITLE variable string is being displayed correctly, we can use the queryByText function and use expect to ensure that everything is ok:

1test("should render get-in-touch title", () => {
2  const { queryByText } = render(<GetInTouch />);
3
4  expect(queryByText(TITLE)).toBeTruthy();
5});

In addition to queryByText other methods are available and you can find the description for them in the testing library documentation

In the end, our test file will look like this:

1import { render } from "@testing-library/react";
2import { useIntl } from "../../hooks/useIntl";
3import { GetInTouch } from ".";
4import { ThemeProvider } from "styled-components";
5import { darkTheme } from "../../styles/themes/dark-theme";
6
7const TITLE = "GET IN TOUCH";
8
9jest.mock("../../hooks/useIntl");
10
11describe("Get In Touch Component", () => {
12  beforeAll(() => {
13    (useIntl as jest.Mock).mockImplementation(() => ({
14      getInTouch: { title: TITLE },
15    }));
16  });
17
18  test("should render get-in-touch title", () => {
19    const { queryByText } = render(<GetInTouch />);
20
21    expect(queryByText(TITLE)).toBeTruthy();
22  });
23});

Running yarn test we can see that the test passed:

test pass

To make sure everything is ok, we can replace expect(queryByText(TITLE)).toBeTruthy(); by expect(queryByText(TITLE)).toBeFalsy();

test fail

That's it!