A Modern Guide to React Unit Testing

Pieces 🌟 - Oct 11 '23 - - Dev Community

A Modern Guide to React Unit Testing.

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:

  1. Configure the necessary dependencies for testing.
  2. 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.
  3. 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
Enter fullscreen mode Exit fullscreen mode

After this, we can proceed to add some extra configurations to our package.json folder:

{
  "scripts": {
    "test": "jest"
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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() });
Enter fullscreen mode Exit fullscreen mode

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:

  1. 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
Enter fullscreen mode Exit fullscreen mode
  1. 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
Enter fullscreen mode Exit fullscreen mode

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!

Generating code with the Pieces Copilot.

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;
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:

Running the above command in the terminal.

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
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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:

The terminal after running the above commands.

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:

Asking the Pieces Copilot to change some text.

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;
Enter fullscreen mode Exit fullscreen mode

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.

Running the npm test.

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.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .