Unit Testing of React Apps using JEST : Tutorial
By Antra Verma, Community Contributor - May 25, 2024
Testing is a crucial aspect that ensures the reliability and stability of our applications. This article guides through the process of unit testing in React applications using Jest, a delightful JavaScript Testing Framework with a focus on simplicity.
- What is Unit Testing in React?
- Why Unit Testing in React is important?
- What to test in Unit Testing for React Apps?
- Prerequisite (Project Setup) of React Unit Testing in JEST
- How to perform Unit testing of React Apps using JEST?
- Mocking Data in React Unit Testing with Jest
- Code Coverage during React Unit Testing using Jest
- Performance Optimization in React Unit Testing
- Accessibility Testing in React using Jest Axe
- Best Practices for testing React Apps with JEST
What is Unit Testing in React?
Unit testing is a type of testing where individual units or components of software are tested. In the context of React applications, a unit could be a React component, a helper function, or any other JavaScript module. The goal is to verify that each unit of the software performs as designed.
Why Unit Testing in React is important?
Unit testing is important for several reasons:
- It helps in maintaining code quality and ensuring that modules behave as expected.
- It makes the process of debugging easier and faster.
- It serves as documentation, providing a detailed description of the system’s design and functionality.
What to test in Unit Testing for React Apps?
In a React application, we can test various aspects such as:
- Component rendering: Ensure that the component renders correctly under different conditions.
- State and props: Test the state changes and the props being received.
- Event handling: Check if the events (like click, and input change) are handled correctly.
- Lifecycle methods: Validate if the lifecycle methods are working as expected.
Prerequisite (Project Setup) of React Unit Testing in JEST
Before starting with testing, a project setup is required. Here are the steps for the same:
1. Install Node.js and npm
Node.js is a JavaScript runtime that is required to run React applications. npm (Node Package Manager) is a package manager for Node.js. It can be downloaded and installed from the official Node.js website.
2. Create a new React application
Once Node.js and npm are installed, a new React application can be created using the create-vite command. The following commands can be run in the terminal or command prompt:
npm init vite@latest jest-react-app --template react
This command creates a new directory named jest-react-app with a new React application.
3. Navigate to the project directory
The current directory can be changed to the newly created React application directory:
cd jest-react-app
4. Install Jest and jest-axe
Jest can be installed as a development dependency using the following command:
npm install --save-dev jest jest-axe
5. Verify Installation
The installation of Jest can be verified by running the following command:
npx jest --version
This command should print the installed version of Jest.
6. Install other required dependencies
Install Axios package
npm i axios
7. Setup running environment
a) Run the following command to install dev dependencies:
npm i –save-dev @babel/preset-react @babel/preset-env @testing-library/jest-dom jest-environment-jsdom
b) Create babel.config.js file at the root of the project and paste the following code:
module.exports = { presets: [ [ '@babel/preset-env', { targets: { node: 'current', }, }, ], '@babel/preset-react', // Adds support for JSX ], plugins: [], };
c) Create jest.config.js file at the root of the project:
module.exports = { testEnvironment: "jsdom", transform: { '^.+\\.(js|jsx|ts|tsx)$': 'babel-jest', }, setupFilesAfterEnv: ['@testing-library/jest-dom'], };
d) Update package.json
Add “test” command in the package.json file,
"scripts": { //other scripts "test": "jest" },
How to perform Unit testing of React Apps using JEST?
Unit testing involves creating test cases for components and running them using Jest. Here are the high-level steps:
- Identify what to test: Determine the functionality that needs to be tested. This could be a function, a component, or an entire feature.
- Write the test: Write a test that checks if the identified functionality works as expected. This involves setting up the necessary environment, executing the functionality, and checking the result.
- Run the test: Use Jest to run the test and check if it passes or fails.
- Analyze the result: If the test fails, analyze why it failed and fix the issue. If it passes, move on to the next functionality to test.
React Testing Library is a lightweight solution for testing React components. It provides simple and complete React DOM testing utilities that encourage good testing practices. The main utilities involve querying for nodes in a way that’s similar to how users would find them. This means tests will be more maintainable and resilient to component structure or styling changes.
Here’s an example of a simple test case using Jest and the React Testing Library:
import React from 'react'; import { render, screen } from '@testing-library/react'; import App from './App'; test('renders learn react link', () => { render(<App />); const linkElement = screen.getByText(/learn react/i); expect(linkElement).toBeInTheDocument(); });
This test checks if the App component renders a link with the text ‘learn react’. This is a simple example of how the React Testing Library can be used with Jest to write unit tests for React applications.
Mocking Data in React Unit Testing with Jest
Mocking in unit testing is like using stand-ins or substitutes for the real parts of your code. This helps you control and check how these parts behave during testing, making your tests more dependable and easier to handle.
Jest, a testing tool, has built-in features that let you create these substitutes for any part of your code, from simple functions to complex parts. This is especially handy when you’re testing parts of your code that need data from outside sources like APIs.
Here’s an example of how to mock data with Jest in a React application:
Consider a User component that fetches user data from an API when it’s mounted:
// User.js import React, { useEffect, useState } from 'react'; import axios from 'axios'; const User = () => { const [user, setUser] = useState(null); useEffect(() => { const fetchData = async () => { const response = await axios.get('https://api.example.com/user'); setUser(response.data); }; fetchData(); }, []); if (!user) { return 'Loading...'; } return <div>{user.name}</div>; }; export default User;
Now, let’s write a test for this component, mocking the axios module to control the data that’s returned by the API:
// User.test.js import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import axios from 'axios'; import User from './User'; // Mocking axios module jest.mock('axios'); test('fetches and displays user data', async () => { // Create a mock response const mockResponse = { data: { name: 'John Doe' } }; axios.get.mockResolvedValue(mockResponse); // Render the User component render(<User />); // Check if the mocked response is used in the component const userNameElement = await waitFor(() => screen.getByText(/John Doe/i)); expect(userNameElement).toBeInTheDocument(); });
In this test, the axios module is mocked using jest.mock(). Then, a mock response is created and axios.get is set to return this mock response when called. The User component is then rendered, which is expected to call axios.get and use the returned data. Finally, it’s checked if the user name from the mock response is present in the document.
Code Coverage during React Unit Testing using Jest
Code coverage is a measure of the extent of code that is covered by tests. It’s a useful metric that can help understand the degree to which the application is tested. Jest can generate a code coverage report by adding the –coverage flag to the test command.
Here’s how the code coverage for the User component test from the previous example can be found:
1. Update the test command:
In the package.json, add the test command in the scripts section.
"scripts": { "test": "jest --coverage", // other scripts... }
2. Run the tests:
The tests can be run with the updated command:
npm run test
3. Check the coverage report:
After the tests have run, Jest will output a code coverage report in the terminal. This report will show the percentage of the code that is covered by tests.
Performance Optimization in React Unit Testing
Performance optimization in testing refers to improving the speed and efficiency of your test suite. Here are some strategies that can be used to optimize the performance of tests:
- Avoid unnecessary rendering: In React, unnecessary rendering can slow down your tests. Make sure to only render the components that are necessary for the test.
- Use shallow rendering: Shallow rendering is a feature provided by libraries like enzyme that renders a component “one level deep” and prevents unnecessary rendering of child components.
- Mock out heavy dependencies: If your component depends on other components or modules that are heavy or slow (like network requests), consider mocking them out using Jest’s mocking features.
- Run tests in parallel: Jest runs tests in parallel by default, which can significantly speed up the test suite. Make sure your tests are not dependent on each other, so they can run in any order.
- Limit the number of snapshots: While snapshot tests can be useful, they can also slow down your test suite and make it harder to maintain if overused. Consider limiting the number of snapshot tests, and prefer explicit assertions whenever possible.
Accessibility Testing in React using Jest Axe
Accessibility testing ensures that your application is usable by all people, including those with disabilities. Jest Axe is a library that integrates with Jest and allows you to run accessibility checks on your React components using the Axe accessibility testing engine.
Here’s an example of how to use Jest Axe for accessibility testing:
//Input.js import React from 'react'; import PropTypes from 'prop-types'; const Input = ({ label, ...props }) => { return ( <div> <label htmlFor="input-field">{label}</label> <input id="input-field" {...props} /> </div> ); }; Input.propTypes = { label: PropTypes.string.isRequired, }; export default Input; //Input.test.js import React from 'react'; import { render } from '@testing-library/react'; import { axe, toHaveNoViolations } from 'jest-axe'; import Input from './Input'; // Add a Jest matcher to check for accessibility violations expect.extend(toHaveNoViolations); test('Input component should have no accessibility violations', async () => { const { container } = render(<Input label="Test input" />); const results = await axe(container); // Assert that there are no accessibility violations expect(results).toHaveNoViolations(); });
In this test, the Input component is rendered with a label. Then, the axe function from jest-axe is used to run accessibility checks on the rendered component. Finally, the toHaveNoViolations matcher from jest-axe is used to assert that there are no accessibility violations.
Best Practices for testing React Apps with JEST
- Write clear, descriptive test cases.
- Test the component behavior, not implementation details.
- Keep tests isolated and independent of each other.
- Regularly update tests when updating component functionality.
Conclusion
Unit testing is a vital part of software development. It ensures code works as expected and helps maintain high-quality standards. With Jest and React, comprehensive unit tests can be written that help build robust, reliable web applications.