How To Unit Test React Applications with Jest: A Beginner's Guide
Tags: webdev, react, testing, javascript
Published: 2023-02-09 15:34:20


Testing plays a crucial part in ensuring the quality and reliability of your code. With the right knowledge of testing, its methods, and tools, you can ensure your code matches the requirements and is bug-free. 

Testing is a critical aspect of software development, yet it is frequently overlooked and undervalued despite its vital role in ensuring the quality and reliability of applications. Testing is important because it helps identify bugs before a software product is released to its end users.

In this article, we'll cover what you need to know about unit testing, getting started with unit testing in your React applications using Jest, from setting up Jest in your project to writing tests.  

##Table of Contents

1. [What Is Unit Testing And Why Is It Important?](#what-is-unit-testing-and-why-is-it-important)
2. [Performing Unit Tests With Jest In React](#performing-unit-tests-with-jest-in-react)
3. [Mocking Functions With Jest](#mocking-functions-with-jest)
4. [Snapshot Testing With Jest](#snapshot-tests-with-jest)
5. [Conclusion](#conclusion)

##What Is Unit Testing And Why Is It Important?

Unit testing is an aspect of the overall testing process in software development. It focuses on individual units of an application such as functions, objects, procedures, and so on. The primary purpose of unit tests is to ensure that each unit performs as expected. 

From the definition above, we can deduce that unit testing in React is the testing of individual React components.  

###Why Is It Important?

Below are some important reasons why we need unit tests.

1. Unit tests help to set the standard for coding requirements; writing tests while implementing a feature, for example, gives us an idea of how the implementation should be written. 
2. It prevents developers push bugs to production as it is always mostly detected in the development phase.
3. Unit testing simplifies the debugging process.
4. Cost-effective - It is cheaper to fix bugs way before a later stage, let's say after it has been pushed to production.

##Performing Unit Tests With Jest In React

> Jest is a JavaScript testing framework designed to ensure the correctness of any JavaScript codebase. It allows you to write tests with an approachable, familiar, and feature-rich API that gives you results quickly.   
>
> -Jest Core Team

Jest in itself is not a library but a framework, it even has a CLI tool that you can use with the command line. Its [official website](https://jestjs.io/) emphasizes its focus on simplicity and that's due to its zero config setup. You can start using it as soon as you install it.

###Setup

- **Create a new React app**

Open your terminal and create a new React app using the command below

```npm
npx create-react-app unit-testing-tutorial
```

- **Install Jest using your favorite package manager**

When you use `cra(create-react-app)` to create a new React project, it has built-in support for Jest, hence we do not have to install it manually. Hence, the only thing you need to do is install `react-test-renderer` for rendering snapshots which will also be covered in this article. You can install it with the command below.

with `npm`
```
npm install --save-dev react-test-renderer
```
with `yarn`
```
yarn add --dev react-test-renderer
```

Otherwise, if you are not using `cra`, you have to install it manually with your favorite package manager with the command below.

with `npm`
```
npm install --save-dev jest react-test-renderer
```  
with `yarn`
```
yarn add --dev jest react-test-renderer
```

Next, add the following code to your `package.json` file

```
{
  "scripts": {
    "test": "jest"
```

###Testing A React Component


> If you used `cra` to create your React app, a `App.test.js` file would have been created for you by default for testing the `App.js` component. To play around, you can run a sample test with the `npm run test` command on your terminal to see how testing works.

In the following steps, we'll get started with testing our own React component with Jest.

- **Step 1: Create a Component**

Let's create a component and call it `MyFirstTest`, which simply renders hello with the name passed to its prop. 

```
import React from "react";

function MyFirstTest({ name }) {
    return (
    <h1>Hello {name}!</h1>
    )
}

export default MyFirstTest;
```

- **Step 2: Create A Test File**

Next, we'll create a test file in the same directory as the component and use the extension `.test.js`. The `.test.js` extension lets Jest know that this is a test file.

The test will check if our component is rendered with the correct name passed to it as a prop. The unit test for our component `MyFirstTest` can then be written as seen below:

```
import { render } from '@testing-library/react';
import MyFirstTest from './MyFirstTest';

test('renders the component with the correct name passed as prop', () => {

  const { getByText } = render(<MyFirstTest name="Peter"/>);
  const textElement = getByText(/Hello Peter!/i);
  expect(textElement).toBeInTheDocument();

});

```
We can describe the above test as:

- We define a test case with the test function provided by Jest. The function takes a string that explains what the test is going to do as its first argument and the second argument is a callback function that implements the test logic.

- Inside the callback function, the first thing we do is render the component we want to test with the render function. The render function returns an object that contains a lot of useful functions that can be used to interact with the rendered component.

- From these functions, we utilize the `getByText` function. This function searches through the rendered component to find an element that contains the text "Hello Peter".

> **NOTE**: The /i at the end of the string /Hello Peter!/i was used to indicate case insensitivity. Hence, "/i" matches the string "Hello Peter" regardless of the case. i.e HeLLo PETER will still match.

- If the component is appropriately rendered, then the element exists in the virtual DOM. We use the `expect` function which gives us access to many [matchers](https://jestjs.io/docs/using-matchers) (like `toBeInTheDocument()`) to assert that the element is in the virtual DOM. If it asserts that it's present, the test will pass. Else, the test fails.

- Run the test with `npm run test` command. Your test result should look like the image below.

![Test Result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qja41lpceiszrjqf70vx.png)

##Mocking Functions With Jest
 
When a function is mocked, it means a sample or epitome of that function is created as a replacement for that function for the purpose of testing. Its purpose is to verify its result or behavior in a predictable environment.

Jest provides several ways we can perform mocking including `jest.fn()`, which we can use to ensure predictable results. With `jest.fn()` we can create a sample(mock function) that can be used to replace the original function for testing purposes. The mock function can then be configured to return specific values or throw new errors. By mocking functions, we can confirm that components are using functions as expected. Let's look at an example of how to mock a function using `jest.fn()` in the following steps.

- Create a file `math.js` and copy the following code.

```js
//math.js
export const add = (a, b) => a + b;
```

- Create another file `add.js` and import the `add` function from the `math.js` file and copy the code below. This way we don't have to worry about the implementation of how the addition is done in the `math.js` file.

```
import { add } from './math.js';

export const doAdd = (a, b) => add(a, b);
```
- Create a test file `add.test.js` and import all exports from the `add.js` file as math. This is so they can be accessible in a math object. 

```
import * as math from './add';

test('adds numbers passed as argument', () => {
const sum = math.doAdd(1, 2);
expect(sum).toBe(3);
});

```
In the code above, we assign the `math.add` function which adds the two parameters passed to it to the variable `sum`. We then use the `expect` method which gives us access to the `toBe()` matcher to assert that the result of the sum is 3.

Your test result should look like this after running the test file

![Test Result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l5yaormr1cf5miwfuar7.png)

##Snapshot Testing With Jest

Snapshot testing is used when you want to catch unexpected changes in your UI. It is a technique used when the output of a test is being compared against a previously captured snapshot of the expected result to ensure consistency. The test passes if the output of the function matches the previously captured snapshot, if it doesn't, the test fails. In the following steps, we'll see how snapshot tests work by testing a `button` component.

- Create a component and name it `button.js` and copy the following code

```
export default function Button() {
    return(
        <button>
            Click Me
        </button>
    )
}
```
- Create a test file `button.test.js` and copy the following code.

```
import React from 'react';
import renderer from 'react-test-renderer';
import Button from './Button';

test('Button should match its snapshot', () => {
  const button = renderer.create(<Button />).toJSON();
  expect(button).toMatchSnapshot();
});

``` 
In the code above:

- We import the `renderer` method from the `react-test-renderer` library that we installed earlier. We then use the `renderer.create` method to render the component.

- After rendering, the `toJSON()` method is called to create a plain JavaScript object that represents the component and its children which is then saved to the variable `button`.  

- We then use the `expect` and `toMatchSnapshot` functions to compare the button with a saved snapshot.

- On testing the file, a `__snapshot__` folder is automatically created where snapshots are stored for comparison. You can think of it as where your history of snapshots is stored. 

Your test result should look like this after you run your test: 

![Test Result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hu6kiyw7hvufkdsm8m4l.png)

If there are any changes later(after the first snapshot was taken), Jest will throw an error and ask if you want to update the snapshot.

As a codebase evolves, Snapshot tests are often used in conjunction with unit tests to ensure that the output of a function remains consistent over time.

###Conclusion

In conclusion, we see that unit testing is a critical aspect of software development that helps to ensure the quality and reliability of our code. It is an efficient way to validate that individual units of code work as intended, reducing the chances of us pushing bugs to production. So far, we have learned about Jest, how we can mock a function with Jest, and how to test using snapshots. Jest has a lot of other features that were not mentioned here, be sure to get your hands dirty. With the right understanding and use of these tools, we can make our testing process more effective and save time.