Testing with Jest and React Testing Library
This post contain affiliate links to Udemy courses, meaning when you click the links and make a purchase, I receive a small commission. I only recommend courses that I believe support the content, and it helps maintain the site.
I have written a number of posts on small niche problems within Jest. From checking if a child component is passed the correct props, to how to correctly mock out the Intl API.
Every time I went to write one of these posts I initially began with an introduction to Jest and React Testing Library. This would then get removed as the piece got more fleshed out.
To fill that gap I have put together this guide/overview of UI testing with Jest and React Components.
What is Jest?
In a brief overview, Jest is an open-source JavaScript testing framework that is widely used with React.
Amongst other things, Jest can be used to create mock functions which can be used to test the behaviour of your React components, take snapshots of UI to check for changes or regressions, and check that flows work in the way that a user will use them.
All tests have a unique global state, which means they can be run in parallel with no overlapping concerns. The beauty of Jest is that it is well-documented and requires little configuration.
A very minimal example of a Jest test looks like this:
import myTest from "./my-test.js"
describe("all the tests for my test function", () => {
test("has a specific case or flow to check", () => {
expect(myTest()).toBe("Some outcome");
});
});
Breaking down what is happening above, we can see:
- describe function = the test suite
- test function = the test case
- expect function = the test assertion
What is React Testing Library?
The React Testing Library is a lightweight library that provides a set of tools for testing React components. These testing functions sit on top of react-dom
, and react-dom/test-utils
. This means that the components being tested act in the same way as they would on a live production website.
You can use the React Testing Library to:
- Test the rendering of your React components
- Test the state of your React components
- Test the interaction with your React components
- Test the lifecycle of your React components
RTL has some super helpful query functions that do most of the heavy lifting for you. For a full overview I would recommend taking a look at their API documentation.
Most Used of React Testing Library Query Functions
Three of the more useful (in my opinion) query functions are:
byRole
Gets the dom element by role (or aria-role). Examples of these would be input
, button
or checkbox
. You can also dial down into this a little more with the byRole
options. If you wanted to get an image by its name <img aria-label="fancy image" src="fancy.jpg" />
you could do: getByRole('img', { name: 'fancy image' })
. Take a look at the Jest documentation for more details.
byText
The byText
utility function searches the dom in the text for any string with specific text. It can be used within getByText
, queryByText
, getAllByText
, queryAllByText
, findByText
, and findAllByText
. For more details see the Jest documentation.
byLabelText
The byLableText
is similar to the byText
query, but is aimed at input fields or similar. This makes it easier to find and add content to inputs, or check that they contain specific values.
Are Jest and React Testing Library the same?
What the difference was between Jest and React Testing Library. Should you use one over the other, i.e. React Testing Library vs. Jest.
Jest and React Testing Library can (and generally are when testing React components) be used together, as they both have different responsibilities. Jest is a test runner. It looks for all files ending with .test.js and runs each test. After running the tests it will return which tests passed or failed, and why they failed.
React Testing Library provides functions that help find and interact with specific DOM nodes within the component being testing. These functions also allow you to run actions on these components, such as:
- rendering
- fireEvent
- waitFor
- screen
How to Set Up and Configure Jest and React Testing Library
To set up and configure Jest and React Testing Library, follow these steps:
Install Jest and React Testing Library by running the following commands:
npm install –save-dev jest
npm install –save-dev @testing-library/react
Create a file named jest.config.js in the root of your project and add the following configuration:
module.exports = {
preset: '@testing-library/react',
};
This will configure Jest to use the React Testing Library preset, which provides some useful defaults for testing React components.
Add the following scripts to your package.json file:
"scripts": {
"test": "jest",
"test:watch": "jest --watch"
}
These scripts will allow you to run your tests using the npm test and npm run test:watch commands.
That’s it! You should now be ready to start writing and running tests with Jest and React Testing Library. Let me know if you have any other questions.
Writing and Running Tests
To write a test, import the render
function from @testing-library/react
, and use it to render the component you want to test. Then, use the various methods provided by render
to make assertions about the component’s behaviour. For example, you could use the getByText
method to check that a button component has the correct text, or the click
method to test that it responds to clicks.
To run your tests, you can use the jest
command in your terminal. By default, Jest will search for and run any files that match the pattern __tests__/*
or end with .test.js
. You can also specify specific files or directories to run, or use options like --watch
to automatically re-run tests when code changes.
Jest provides a rich set of features for organizing and running your tests, including support for running tests in parallel, mocking dependencies, and snapshot testing. In the next section, we will discuss some best practices for writing tests with Jest and React Testing Library.
How to Mock a Function with Jest
Mocking a function with Jest is relatively simple. It is a three step process.
- Import the dependencies
- Mock the dependency
- Fake the function output to test that the function works as required.
This follows the flow of three As in unit tests:
- Arrange: set up the environment and the state of date for testing.
- Act: call the test, and run the function to perfect the action.
- Assert: Check that the output and side effects are returns as expected.
Read more about the three As of unit testing here.
Here is a simple example of a test laid out to follow the AAA pattern.
Function to test
import getFirstNumber from '../getFirstNumber';
const addNumber = (value) => {
const result = getFirstNumber() + value;
return result;
}
Testing the function
// Import all the modules
import getFirstNumber from '../getFirstNumber';
import addTwoNumbers from '../addTwoNumbers';
// This is a function that is not being tested, so we mock it out
jest.mock('@../getFirstNumber');
describe('addTwoNumbers', () => {
test('If getFirstNumber is 1, total is 3', () => {
// Arrange
getFirstNumber.mockReturnValue(1);
const argA = 2;
const assert = 3; // Act
const result = addNumbers(argA); // Assert
expect(result).toBe(assert);
});
});
If you are looking to mock a whole React component I would suggest looking at this article on how to mock a React component in Jest.
Testing Best Practices
When writing tests with Jest and React Testing Library, it’s important to follow some best practices to make your tests effective and maintainable. One of the key principles of testing is to test the behaviour of your components rather than their implementation. This means that your tests should not rely on the internal details of your components, but rather focus on how the components interact with the rest of your application.
Another important practice is to keep your tests focused and independent. Each test should test a specific behaviour of a component, and should not depend on the state or behaviour of other tests. This makes it easier to understand and debug failing tests, and also allows you to run your tests in parallel to save time.
Jest provides some powerful tools for testing React components, such as mocking dependencies and snapshot testing. Mocking allows you to replace real dependencies with fake versions that are controlled by the test, which makes it easier to test how your components behave in different scenarios. Snapshot testing allows you to automatically verify that the structure of your components has not changed, which can be useful for catching unintended changes. In the next section, we will discuss how to use these features in your tests.