Testing, which is a stage in the Software Development Life Cycle (SLDC), is a concept that may be new to developers who haven't pushed a product live or beginners who are still in the bubble of personal projects and tutorials. It entails testing code for bugs and determining whether or not it meets the customer's requirements.
Software development does not stop at writing code! A few other questions need to be answered in order for that code to be successful. Does the code work? Does it meet the customers' standards? Is it error-free? All these have to be properly addressed at the software testing stages before pushing the codebase to production.
Unit testing, one of the types of software testing, means testing the functionality of a particular component in isolation, or as a unit. In this tutorial, you will learn all about React unit testing, how to write unit tests in React, how to install the Jest testing library, snapshot testing, and how to implement snapshot testing in React.
Prerequisites
This tutorial will be explained in straightforward terms for easy comprehension, but to properly follow it, you must possess knowledge of the following:
What is Unit Testing and Why is it Important?
Consider a scenario where you have a particular codebase and to make things easier, you choose to separate sections or components of the codebase to test for errors. This procedure is known as unit testing. It is a type of software testing where code is separated into units and each unit is tested individually to ensure it runs as expected. Unit testing is an important stage in software development for the following reasons:
- Improves Quality and Maintainability of your Codebase: Writing unit tests improves the quality and maintainability of your codebase by making it less prone to error. Having to run into several bugs in the course of maintaining code may be exhausting, especially over a long period. Writing good unit tests fixes this. Also, writing tests enables flexibility in coding since the developers will be alerted as soon as bugs (code that contradicts the tests that have been written) are spotted.
- It serves as documentation for your Codebase: By explicitly writing tests that define how a piece of code should behave, it provides context that you would normally add at the documentation stage of software development. However, with the help of Pieces for Developers, you can do that long process and easily allow the app to provide context for you by simply copying the piece of code.
- Improved Understanding of Codebase: Separating each component into individual components and treating each as a unit helps developers have a proper understanding of the codebase since each unit will have to be properly assessed and tested for errors.
Structure of Unit Testing in React
Whether you're writing React unit tests for your project or a production-level codebase, it follows these key steps:
- Configure the necessary dependencies for testing.
- Give an instance or a simulation of a user's interaction. This may include manually calling a function that would be normally triggered when a button is clicked on.
- Write an assertion based on the behavior of the particular component. A test is successfully passed if the result matches the expected outcome.
Installation of React Testing Libraries
To implement unit testing in React, we will be using two of the most popular React testing libraries, Jest and Enzyme.
Jest Unit Testing
Jest is a testing library for JavaScript and its frameworks. It supports React, Vue, and Angular. It is designed to ensure correctness in any JavaScript codebase. We can use Jest in our application by opening our terminal and installing it from Node Package Manager (NPM) using the following line of code:
npm install --save-dev jest @testing-library/jest-dom
After this, we can proceed to add some extra configurations to our package.json
folder:
{
"scripts": {
"test": "jest"
}
}
And we're set! We can then proceed to Jest for unit testing of our codebase. But first, let's see how we would install Enzyme in our application.
Enzyme
Enzyme is a JavaScript testing tool made specifically to test React components and perform other unit testing exercises. Using Enzyme and Jest together is the most seamless method for testing your React components. You can install Enzyme by opening your terminal and running the following line of code:
npm i --save-dev enzyme enzyme-adapter-react-16
Note that you install the version of Enzyme that corresponds with your version of React. In this article, we will be using React version 16, hence the specification of react-16
. We can then proceed to make further configurations to the Enzyme Adapter in your App.js
file:
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
Writing A Unit Test in React
In this section, we will write our first unit test with a sample project but first, we have to create a new React Application.
Scaffolding React Application
We can create a new React app by following these steps:
- Open your terminal and run the command below to create a new React application called
pieces-test-tutorial
. We will be using Next.js as our build tool.
npx create-next-app pieces-test-tutorial
- Define a custom directory and then proceed with the run command so our app runs on the browser.
cd pieces-test-tutorial
npm run dev
And we’re set! Now let's work with some mock content.
Creating Demo Project
In this section, we want to perform React component testing that confirms if a string of text is present within an element. If there is a match, the test passes; otherwise, it fails. Let's start by creating our text component. Rather than manually create the component, I will use the Pieces Copilot which generates the code snippets for me. All I have to do is ask!
Here, I made a quick request to the Pieces Copilot to Generate a React Code that has a TestFile
function that outputs the text "Copy and Save code snippets with Pieces", and it does that perfectly! Now we can proceed to use the snippet.
Here's the generated snippet from the Pieces Copilot:
import React from 'react';
function TestFile() {
return (
<div>
<h1>Copy and Save code snippets with Pieces</h1>
</div>
);
}
export default TestFile;
Here's a simple component named TestFile.js
that renders a text that says "Copy and save code snippets with Pieces", which is one of the use cases of the Pieces for Developers App. Now, we want to run a test that confirms that the text is present in the element. We proceed by creating our test setup file. First, let's import the necessary packages.
import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react";
import TestFile from "./TestFile.js";
Here, we import the testing library from jest-dom
and jest
which we installed through our terminal earlier, also the render
and screen
methods that we will be using to perform the text comparison to ensure there is a match. We create a .test.js
file in our root folder and configure it like this:
import "@testing-library/jest-dom";
import React from "react";
import { render, screen } from "@testing-library/react";
import TestFile from "./TestFile.js";
test("Text matches", () => {
render(<TestFile />);
const messageElement = screen.getByText(/Hello, World!/i);
expect(messageElement).toBeInTheDocument();
});
Here, we use the test()
method to simulate an interaction. We named the title of our text "Text matches" so it could either return a PASS or FAILED depending on whether the test was successful. You can rename the title to one that suits you.
In the function, we render the TextFile
component, as we imported the render method from our testing-library
earlier. After that, we create a variable messageElement
which we use to get the text from the element if it exists (remember it's a test). Finally, we use the expect()
method to compare if there's a match. We're basically saying "Hey, I expect this text to be in the document, can you help me check if it is?"
Testing the Component
Now that we've created our test setup, we can check if there's a match. How do we do this? Jest provides a default test command that performs a quick check on the correctness of a component. Open your terminal and run the test command below:
npx jest .test.js
We're testing the .test.js
file because that's what we named our test file. (Note that it's npx,
not npm
.) When we run the command, we get a log report of the test and whether it passes or fails.
Here's what our terminal looks like when we run the command:
Here, we see that our test passes as we expect it to because the text matches. If we change any of the characters so that it doesn't match, the test fails. We have successfully run a unit test for our TestFile.js
component and can confirm that it works. In the terminal, we notice a report that says Snapshots: 0 total
. What's that about?
React SnapShot Testing
Snapshot testing deals with a comparison of a particular image of a codebase to the previously saved image of the codebase. If the data in a snapshot matches the data in the previously saved snapshot, the test passes, otherwise it fails. It helps in spotting any changes to the output or unexpected code changes. Jest helps highlight code differences between two snapshots when compared.
Snapshot Testing with Jest
We can implement snapshot testing with Jest in our React application. First, we have to install the react-test-renderer
utility that helps render the code at the test. We do that by running the following line of code:
npm install --save-dev react-test-renderer
Now we can proceed to compare snapshots. We start by creating the first instance of a snapshot by making some changes to our .test.js
file as shown below:
import "@testing-library/jest-dom";
import React from "react";
import renderer from "react-test-renderer";
import TestFile from "./TestFile.js";
test("renders correctly", () => {
const component = renderer.create(<TestFile />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
Here, we import the renderer
method from the react-test-renderer
package we installed earlier. Then, we make a snapshot of the TestFile
that we generated with the Pieces Copilot. The text of the element remains unchanged here. We run our test using the npm run test
command. When we run the command, this is what our terminal looks like:
Here, we have created the first snapshot. If we run another test, nothing changes because there will be no conflict with the first snapshot. Let's make some changes to our TestFile.js
. I'll just head over to the Pieces Copilot and let it do that for us:
And there! A new code snippet with the text, "Convert from one programming language to another using Pieces" (another use case of Pieces) is generated. Here's the output:
import React from 'react';
function TestFile() {
return (
<div>
<h1>Convert from one programming language to another using Pieces</h1>
</div>
);
}
export default TestFile;
Now we have different code from the first snapshot. The text of the first snapshot was "Copy and Save code snippets with Pieces" whereas this one is "Convert from one programming language to another using Pieces"— much different! Let's take a look at the behavior of the terminal when we try to get another snapshot using the npm run test
command.
Here, we see that our test fails because there's been a text change. The previous snapshot (which serves as a benchmark) is different from the new snapshot. It goes further to highlight the text change and why it failed the test. This is known as snapshot testing.
Conclusion
By following this tutorial, you have learned about React unit testing, why it is important, how to write unit tests, how to get started with the Jest and React testing libraries, how to generate code snippets using the Pieces Copilot, the concept of snapshot testing, and how to implement snapshot testing using Jest.
The next step will be to check out other types of test practices in software engineering. You can click here to download the Pieces Desktop app and try out some more exciting stuff. Have fun!
P.S. Not sold on React? Read our guide on Svelte vs React and which one is better for your development projects.