Using Jest and RTL with React and TypeScript
In previous posts we have configured a React and TypeScript app to be bundled by Webpack 5. Our Webpack configuration included the handling of CSS and images.
In this post, we will install and use Jest and React Testing Library to write tests on a couple of components in our app.
Installing Jest And React Testing Library
We’ll start by installing Jest and its TypeScript types:
npm install --save-dev jest @types/jest
We can now install React Testing Library:
npm install --save-dev @testing-library/react
We will also install jest-dom
which gives us useful matchers to use on the DOM.
npm install --save-dev @testing-library/jest-dom
Let’s add a npm script to run our Jest tests in package.json
:
{
"scripts": {
...,
"test": "jest"
}
}
Configuring Jest
We can import jest-dom
in a Jest setup file so that we don’t have to import it into each test file.
First, we will create the a Jest setup file in the root of the project called jest-setup.ts
. We’ll add the following import statement into it:
import '@testing-library/jest-dom'
We can tell Jest about the setup file in its configuration section in package.json
. Add the following jest
field to package.json
:
{
...,
"jest": {
"setupFilesAfterEnv": [
"<rootDir>/jest-setup.ts"
]
}
}
Creating a test
Let’s create a test for the Header
component in a file called Heading.test.tsx
:
import React from "react";
import { render, screen } from "@testing-library/react";
import { Heading } from "./Heading";
test("Header contains correct text", () => {
render(<Heading />);
const text = screen.getByText("My React and TypeScript App");
expect(text).toBeInTheDocument();
});
The test checks that the content of the heading is correct.
If we run npm test
to execute the test, we get a “Unexpected token ’.‘” error:
The problem is that Webpack isn’t executed in a Jest test, so the CSS module hasn’t been resolved.
Mocking CSS modules
We aren’t testing the specific styles from the CSS module in the Header
component, so we can mock this out using moduleNameMapper
and a library called identity-obj-proxy
.
Let’s install identity-obj-proxy
:
npm install --save-dev identity-obj-proxy
Let’s add the following to Jest configuration in package.json
:
{
...,
"jest": {
...,
"moduleNameMapper": { "\\.(css|less)$": "identity-obj-proxy" } }
}
When Jest comes across the {heading.heading}
class name, identity-obj-proxy
will replace it with 'header'
, which mocks the CSS module out.
If we rerun the test, it passes:
Mocking images
Let’s create a test for the Content
component in a file called Content.test.tsx
:
import React from "react";
import { render, screen } from "@testing-library/react";
import { Content } from "./Content";
test("Content contains var image", () => {
render(<Content />);
const car = screen.getByAltText("Car");
expect(car).toBeInTheDocument();
});
If we rerun our tests (npm test
), we get a “Invalid or unexpected token” error:
The problem is that Jest doesn’t understand the image import.
Our test is only checking that an image element is contained within the Content
component. So, we can mock the specific car image path using moduleNameMapper
in the Jest configuration. Add the following to package.json
:
{
...,
"jest": {
"moduleNameMapper": {
...,
"\\.(jpg|jpeg|png|gif)$": "<rootDir>/src/__mocks__/fileMock.ts" }
}
}
Let’s add the following content in our mock file at src/__mocks__/fileMock.ts
:
export default "test-file-stub";
Image paths in our React components will now be replaced with “test-file-stub” in our Jest tests.
If we rerun our tests (npm test
), they will now pass:
Nice! 😊
That’s it! Our React and TypeScript project now has some passing tests.
This code is available in GitHub at https://github.com/carlrip/react-typescript-jest-webpack.
Did you find this post useful?
Let me know by sharing it on Twitter.If you to learn more about testing React apps, you may find my course useful: