Not long ago that I came across with the concept of testing specifically "writing tests". I used to test everything by opening browsers and doing everything manually but you can't know what can go wrong when you change something in your code, and usually it does.
The point is that real apps need testing to ensure that our features will not break unexpectedly, instead of testing the app yourself you write tests that you can run anytime to ensure that everything still works as expected.
In this tutorial I will walk you through the process of setting up Jest and React testing library (RTL) for testing React applications
Note: this is a third article in the series of setting up a React environment from scratch without create-react-app
as Jest and React Testing Library are already included in CRA. in the first article, we created a brand new React project from scratch without using create-react-app
, the second article we configured ESLint, Prettier and Husky and we will base on this progress to setup a Jest and RTL and write our first test.
You can find code from last article HERE
Prerequisites
I will assume that you have a react app running and everything we built from previous articles, you can also follow along if you need this article for other purposes but note that your code may look different than what I have but the idea should be the same.
VS code: I will be using Vs code as our code editor but feel free to use any of your preference
that's all you need let's get started
Why testing?
Tests can be boring to write and useless in some cases but I can't stress enough the importance of testing extensively your application. how you ensure that your app still works after adding new code? => you write tests, how do you spot bugs that you never though they existed? by writing test. it is recommended that you test everything you write to have confidence that your app is running as expected. Testing is very strictly enforced at many organizations and some use the Test-driven development where tests are written before you implement features
Jest
Jest is an open source test framework created by Facebook and is well integrated with React. it have many built-in like snapshot testing, function mocking, coverage collection and is usually easy to configure and use. In this configuration, we will be using Jest to run tests that we write and know which failed or passed and collect coverage (meaning tell us lines that are not covered/tested in our codebase). learn more about Jest here
React Testing Library
React testing library (RTL) is a lightweight testing Library that help us to test React by simulating how users will interact with our application. as mentioned Here the official React documentation recommends using RTL to encourage writing tests that use your components as the end users do. learn more about RTL here
in our example we will be using both Jest and RTL but note that any can be used on it's own or with other tools. for better testing we will be using React testing Library to find our components and manipulate them while Jest will determine passing and failing tests and testing coverage
This guide will be more of configuration so I won't cover much about writing tests. for more about details about testing React applications check this great article here
Enough with the talking. let's get this party started. Follow the following steps
1. Install React testing library dependencies
- run the following command to install RTL dependencies (as dev dependencies)
npm install --save-dev @testing-library/react @testing-library/jest-dom
if you prefer yarn
yarn add --dev @testing-library/react @testing-library/jest-dom
-
@testing-library/react
: the core dependency that install react testing library. -
@testing-library/jest-dom
: is a virtual DOM for jest allow us to use custom jest matchers to extend jest with react testing library. there matchers will make your tests more declarative, clear to read and to maintain. More on this later
2. Install Jest dependecies
- run the following command to install jest dependencies (as a dev dependecies)
npm install --save-dev jest jest-environment-jsdom
if you prefer yarn
yarn add --dev jest jest-environment-jsdom
-
jest
: the core dependency required for Jest to work -
jest-environment-jsdom
: this will allow us to usejsdom
and we will use it together with@testing-library/jest-dom
that we installed earlier
3. Configure Jest
You can configure Jest by adding jest entry in the package.json
or add a file named jest.config.js
in the root folder. To keep package.json
clean we will use jest.config.js
- Create a file named
jest.config.js
in the root folder and add the following code configuration.
module.exports = {
collectCoverage: true,
collectCoverageFrom: ['src/**/*.{js,jsx}'],
coverageDirectory: 'coverage',
testEnvironment: 'jsdom',
}
Understand this configuration
-
collectCoverage
: enables collecting coverage -
collectCoverageFrom
specifies files to collect coverage from this will be from files files in all.js
andjsx
from src folder -
coverageDirectory
specifies folder jest will put coverage files -
testEnvironment
The test environment that will be used for testing note that we are setting it tojsdom
and this will be coming from@testing-library/jest-dom
andjest-environment-jsdom
packages we installed earlier.
Most of jest configurations are well configured by default so we don't need to edit much in this file, but you can customize everything however you want. Learn more about all configurations and their values HERE
4.Integrate Jest with React testing Library
- in the root folder create a file named
jest.setup.js
enter the following line of code
import '@testing-library/jest-dom'
this means that we are importing everything from @testing-library/jest-dom
package
- in the
jest.config.js
file we created earlier add another field ofsetupFilesAfterEnv
and set it's value to be['<rootDir>/jest.setup.js']
this will tell jest for every test we write it will load configuration fromjest.setup.js
i.e. use React testing libraly yourjest.config.js
should look like this
module.exports = {
collectCoverage: true,
collectCoverageFrom: ['src/**/*.{js,jsx}'],
coverageDirectory: 'coverage',
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
};
5.Integrate Jest with ESLint
In the second article we setup ESLint to help us clean code. By default if you use Jest with Eslint installed Eslint will give errors because with Jest tests we use some functions directly without importing them, and ESLint doesn't accept that, therefore we need to integrate Eslint with Jest
follow the following steps, if you don't have Eslint in your project you can skip this section
- Run the following command to install
eslint-plugin-jest
which will make Eslint recognise Jest code
npm install --save-dev eslint-plugin-jest
yarn add --dev eslint-plugin-jest
- in the
eslintrc.json
add"jest"
in the plugins array - in the
eslintrc.json
add"plugin:jest/recommended",
in theextends
to use recommended jest syntax - in the
eslintrc.json
in theenv
entry add"jest/globals": true
to enable jest in our eslint environment
Your eslintrc.json
should end up looking like this
{
"env": {
"browser": true,
"es2021": true,
"jest/globals": true
},
"extends": [
"plugin:react/recommended",
"plugin:jest/recommended",
"airbnb",
"prettier"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["react", "jest"],
"rules": {
"no-underscore-dangle": 0,
"import/extensions": [
"error",
"ignorePackages",
{
"js": "always",
"jsx": "always"
}
]
}
}
6. Adding testing scripts
in the package.json
in the script object add the following scripts
scripts:{
... //scripts you already have
test: "jest",
coverage: "jest --coverage"
}
test: "jest"
: will find all our test to which whicha passing and failing
coverage: "jest --coverage"
: will run our tests too and also collect our coverage
That's all the configuration now you can write some tests
Writing tests
By convection we create a folder called test
or __test__
in the folder you have files you want to test and tests will have name foo.test.js
or bar.test.js
- in the
src
folder create atest
folder and addApp.test.jsx
to testApp.jsx
and the following code
import { render, screen } from '@testing-library/react';
import React from 'react';
import App from '../App.jsx';
describe('App tests', () => {
it('should contains the heading 1', () => {
render(<App />);
const heading = screen.getByText(/Hello world! I am using React/i);
expect(heading).toBeInTheDocument()
});
});
- run test by running
npm run test and it should pass
in this test we are testing that we have text Hello world! I am using React
in our page, and this should pass as that's the text we used in article 1
There you have it that's how we setup Jest and React Testing Library to test React applications
For reference of code mentioned in this article check this GitHub repository
Top comments (17)
Everything looks very simple and clear, thanks for the guide. I just recently started diving into the world of programming by picking up math from textbooks with plainmath.net/textbooks/math/calculus just for myself. So now I'm collecting different guides to better understand how it all works and where to start. I'm interested in learning React now and I'm thinking of taking some more courses to get practical skills and a certificate to work with.
The series is going great :)
Wow.. It work. thank you
I did exactly what you did but I'm getting Syntax Error can't use import outside of module.
This is my package.json
{
"engines": {
"node": "14.20.0",
"npm": "6.x.x"
},
"name": "ui-v2",
"version": "0.1.0",
"private": true,
"dependencies": {
"@amcharts/amcharts3-react": "^3.1.1",
"@amcharts/amcharts4": "^4.10.35",
"@emotion/react": "^11.11.0",
"@emotion/styled": "^11.11.0",
"@material-ui/core": "^4.12.4",
"@mui/icons-material": "^5.11.16",
"@mui/material": "^5.13.0",
"@reduxjs/toolkit": "^1.9.5",
"file-saver": "^2.0.5",
"firebase": "^9.9.0",
"inflected": "^2.1.0",
"javascript-color-gradient": "^2.4.4",
"jquery": "^3.7.0",
"jqueryui": "^1.11.1",
"moment": "^2.29.4",
"plotly.js": "^2.23.0",
"rc-slider": "^9.7.5",
"react": "^17.0.2",
"react-cookies": "^0.1.1",
"react-dom": "^16.14.0",
"react-dropdown-tree-select": "^2.8.0",
"react-grid-layout": "^1.3.4",
"react-helmet": "^6.1.0",
"react-https-redirect": "^1.1.0",
"react-phone-input-2": "^2.15.1",
"react-plotly.js": "^2.6.0",
"react-popup": "^0.10.0",
"react-redux": "^8.0.5",
"react-router-dom": "^5.3.4",
"react-scripts": "^5.0.1",
"react-select": "^4.3.1",
"react-table": "6.9.0",
"react-trello": "^2.2.11",
"redux": "^4.2.0",
"shortid": "^2.2.16",
"tabulator-tables": "~4.9.3",
"uikit": "~3.11.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "jest",
"coverage": "jest --coverage",
"eject": "react-scripts eject"
},
"client": {
"machine_name": "pi",
"categoryToolkit": true,
"isAdmin": true,
"version": "2.87.0.17"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"devDependencies": {
"@babel/plugin-transform-private-property-in-object": "^7.21.11",
"@redux-devtools/core": "^3.13.1",
"@svgr/webpack": "^6.2.1",
"@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^14.1.2",
"eslint-plugin-jest": "^27.6.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"resolve-url-loader": "^5.0.0",
"webpack-dev-server": "~4.10.0"
},
"overrides": {
"@svgr/webpack": "$@svgr/webpack",
"resolve-url-loader": "$resolve-url-loader",
"webpack-dev-server": "$webpack-dev-server"
}
}
my jest.config and jest.setup are exactly the same
What am i missing here?
@sarahfarjallah Try also adding
"type": "module"
in yourpackage.json
Sadly it didn't work
My project is a typescript one, so I changed the config you suggest to the below and it works pretty well. Practical read, great help, thanks
module.exports = {
collectCoverage: true,
collectCoverageFrom: ['src/**/*.{ts,tsx}'],
coverageDirectory: 'coverage',
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/jest.setup.js']
}
It works thanks , This article is really helpful , but one question in my project there is file setupTests.js in which import '@testing-library/jest-dom' is done and works but doing a separte file jest.setup.js does 'nt work
I have a problem in my project. Previously, enzyme and jest were used for testing. But when we updating the react version, enzyme became deprecated. So it was decided to start using Jest with React testing library.
I did all the installation´s steps that is detailed in this post, but when running jest I get the error TypeError: Cannot destructure property 'config' of 'cacheKeyOptions' as it is undefined. Could someone help me to solve it?
Nice easy to follow guide.
It is depressing to read create a .js (JAVASCRIPT FILE) file and write import "@testing-library/jest-dom" (TYPESCRIPT SYNTAX)
Thank you again!!