Testing is one of the most crucial steps in building an application; it helps to erase harmful bugs and gives your project credibility and quality assurance.
The React community has produced a large number of libraries for testing components and functions in React applications. This post highlights some of the top choices for testing React applications.
Jest
Jest, a testing framework created and maintained by Facebook, has been widely adopted by other companies such as Airbnb, Uber, and Amazon. React ships with Jest out of the box so you don’t need to install as a dependency.
Getting started with Jest
There are two ways to begin testing with Jest. First, for a project initialized with create-react-app
, install using a node manager as seen below:
// NPM npm install -D react-test-renderer // Yarn yarn add -D react-test-renderer
The above command installs react-test-renderer
in the application for use in snapshot testing.
Next, copy the command below to install the package for DOM testing in a React app using Jest.
// NPM npm install -D @testing-library // Yarn yarn add -D @testing-library/react
For applications not initialized with create-react-app
, you will need to follow the steps below.
First, add the following packages as dev dependencies:
npm install --dev jest babel-jest @babel/preset-env @babel/preset-react react-test-renderer
Next, add the Babel configuration:
// babel.config.js module.exports = { presets: ['@babel/preset-env', '@babel/preset-react'], };
Next, include jest
in your application’s package.json
:
{ "scripts": { "test": "jest" } }
Now, you’ll write a simple test for your React app’s component:
import React from "react"; import { cleanup, render } from "@testing-library/react"; import { FootLabel } from './FootLabel describe("FootLabel", () => { test("component should display label", () => { const { getByText } = render(<FootLabel label="Test" />); expect(getByText("Test")).toBeTruthy(); }); });
The test above uses Jest’s method describe
to represent components similar to FootLabel
and test what the component looks like against the expected output.
In addition to testing a component’s expected result against its actual output, Jest also performs snapshot testing.
A snapshot test makes sure that the user interface of an application does not change unexpectedly. Snapshot testing in Jest allows a user to compare a component in one state with any other state it might take. Snapshots are especially useful in projects with global styles that are used across components.
import React from "react"; import renderer from "react-test-renderer"; import Navbar from "./Navbar.js" describe("<Navbar />", () => { it('renders correctly across screens', () => { const tree = renderer.create().toJSON(); expect(tree).toMatchSnapshot(); });
Some of the pros of using Jest include:
- Variety: Jest offers snapshot, asynchronous, and parallelization tests
- Mocking: Jest offers the ability to mock API functions and third-party libraries
- Control: Jest features a code and syntax report guide
One of the cons of Jest is that it requires other third-party testing frameworks such as Enzyme to improve its performance. Additionally, it might struggle when used on large projects that feature different types of tests, such as integration tests.
You can see the Jest documentation to learn more about testing with Jest.
Mocha
Mocha is a JavaScript framework that runs on Node.js and is used to test React applications. It boasts browser support, async testing and use of assertion libraries. With Mocha, a developer has complete control over which tools and plugins to use when testing applications. Due to the specific configurations and features it provides for testing React apps, Mocha excels in mocking tests.
Installation
To test React apps with Mocha, first install Mocha as a dev dependency on your React project using the command below:
npm i --save-dev mocha
If you’re using Yarn as your package manager, then use this command:
yarn add mocha
Then update the test
script in your package.json
to include Mocha:
{ "scripts": { "test": "mocha" } }
See usage below:
// test/test.js var modal = require('modal'); describe('Array', function() { describe('#indexOf()', function() { it('should return 0 when the value is not present', function() { assert.equal([1, 2, 3, 4, 5].indexOf(6), -3); }); }); });
The test above searched for a number 6
in the array and returned -3
if the index of the number was not found.
Some of the pros of using Mocha include the following:
- Supports behavior-driven-development (BDD) and test-driven-development (TDD)
- Features easy async testing
- Supports generators to easily test suites when it is required in the test file
- Offers highly extensible support for various assertion and mocking libraries
You can read more about Mocha in its official documentation.
Jasmine
Jasmine is a simple JavaScript testing framework for browsers and Node.js. Jasmine follows a behavior-driven-development pattern, so configuration is generally in place before use. With Jasmine, developers can test for the visibility and resolution of user interfaces on different devices. To use Jasmine in testing React applications, developers can add other third-party frameworks such as Enzyme.
Installation
Developers often use Jasmine in tandem with Enzyme, so it needs to be installed as part of the configurations.
yarn add -D babel-cli \ @babel/register \ babel-preset-react-app \ cross-env \ enzyme \ enzyme-adapter-react-16 \ jasmine-enzyme \ jsdom \ jasmine
Next, initialize Jasmine using the command below:
// For NPM npm run jasmine init // For Yarn yarn run jasmine init
Jasmine requires putting all configuration files, including Babel, Enzyme, and JSDOM, in a spec
folder.
// babel.js require('@babel/register'); // for typescript require('@babel/register')({ "extensions": [".js", ".jsx", ".ts", ".tsx"] }); // enzyme.js or enzyme.ts // be sure your file extension is .ts if your project is a typescript project import jasmineEnzyme from 'jasmine-enzyme'; import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; configure({ adapter: new Adapter() }); beforeEach(function() { jasmineEnzyme(); }); // jsdom.js import {JSDOM} from 'jsdom'; const dom = new JSDOM('<html><body></body></html>'); global.document = dom.window.document; global.window = dom.window; global.navigator = dom.window.navigator;
Next, navigate into your project file to work with spec/support/jasmine.json
and edit the configuration to enable other third-party libraries work with Jasmine.
// for normal projects "helpers": [ "helpers/babel.js", "helpers/**/*.js" ], // for typescript projects "helpers": [ "helpers/babel.js", "helpers/**/*.{js,ts}" ],
Most of Jasmine’s test architecture and helper functions are very similar to Jest.
Some of the pros of Jasmine include the following:
- Does not require DOM to test
- Can be used for frontend and backend tests
- Can be used for asynchronous function tests
- Features a custom equality checker assertion
- Comes with an inbuilt matcher assertion
Despite its benefits, Jasmine isn’t the perfect testing framework for React apps. It doesn’t support snapshot tests, and it requires third-party libraries for parallelization and Native DOM manipulation.
Enzyme
Enzyme is a JavaScript testing utility for React that makes it easier to test your React Components’ output. Developed and maintained by Airbnb, Enzyme is widely used by developers in tandem with other third-party libraries such as Jest and Chai.
To use Enzyme, install:
npm i -D enzyme enzyme-adapter-react-16
Next, create a file enzyme.js
in your src
directory and write the code block below
import Enzyme, { configure, shallow, mount, render } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; configure({ adapter: new Adapter() }); export { shallow, mount, render }; export default Enzyme;
Here, you’ll do a shallow test of a component using Enzyme below:
import React from 'react'; // we are importing from our enzyme.js import { shallow } from './enzyme'; import FootNav from './FootNav'; describe('FootNav', () => { test('renders correct text in component', () => { const wrapper = shallow(<MyComponent label="Contact Fortune" />); expect(wrapper.find('.my-label').get(0).props.children).toEqual('Contact Fortune'); }); });
In the test above, you imported shallow
from Enzyme and a FootNav
component. Next, you described the component and checked to see if it rendered correctly and returned the expected text, which in our case is Hello Fortune
. To finish the test, you put in our expectation, which is that the first child of the array returns the text, Hello Fortune
.
Advantages of Enzyme include the following:
- Supports shallow rendering
- Features support for DOM rendering
- Supports use of react-hooks in shallow rendering
- Can simulate a runtime against the test output
Despite being a powerful test framework, Enzyme has a number of disadvantages. For one, Enzyme is built on a custom react-dom
, so it sometimes can’t support certain new React features. For another, Enzyme encourages the use of ID and CSS selectors, which sometimes break the code when refactored.
You can learn more about Enzyme by reading the official documentation.
React Testing Library
With more than 12M downloads a month, React Testing Library is one of the most widely-used testing frameworks for React applications. It was created by Kent C. Dodds and is currently supported by the open source community. React Testing Library allows developers to test components to simulate a user’s behavior easily. Additionally, it comes built in with React DOM testing utilities that emulates actual user actions on a React application.
To use React Testing Library, first install using the code block below:
npm install --save-dev @testing-library/react
Or using Yarn:
yarn add --dev @testing-library/react
Usage
import * as React from 'react' function Modal({children}) { const [showModal, setShowModal] = React.useState(false) return ( <div> <label htmlFor="toggle">Hello, This is a modal</label> <input id="toggle" onChange={e => setShowModal(e.target.checked)} checked={showModal} /> {showModal ? children : null} </div> ) } export default Modal
React Testing Library supports both Hooks and classes, so tests are consistent whether you use class or function components.
Some pros of using React Testing Library include:
- Supports user behavior testing
- Comes inbuilt with DOM testing utilities
- Makes it easier to emulate user workflows and actions
- Is compatible with other UI frameworks such as angular and Vue.
Some cons of React Testing Library include a lack of support for shallow rendering and inability to access component state.
Summary
Testing React applications is very important to development today. These libraries make it easier than ever to create better React applications and improve the overall user experience. Libraries like Jest are better suited for testing larger projects, whereas other libraries like React Testing Library are better suited for testing user behaviors and support class or function components.
Get set up with LogRocket's modern React error tracking in minutes:
- Visit https://logrocket.com/signup/ to get an app ID.
- Install LogRocket via NPM or script tag.
LogRocket.init()
must be called client-side, not server-side. - (Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- ngrx middleware
- Vuex plugin
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>