Table of contents
1.
Introduction
2.
Jest Setup for Snapshot Testing
2.1.
Link.js
2.2.
Link.test.js
2.3.
Output
2.4.
Link.test.js
3.
Jest Setup for Mock Testing
3.1.
Mocking React Component
3.1.1.
Create 3 file named component1.js, component2.js and component3.js and write the respective code given below:component1.js
3.1.2.
component3.js
3.1.3.
component3.test.js
3.2.
Mocking Function using Jest
3.2.1.
Package.json
3.2.2.
app.js
3.3.
Mocking External APIs using Jest:
3.3.1.
app.js
3.3.2.
app.test.js
4.
FAQs
5.
Key Takeaways
Last Updated: Mar 27, 2024

Testing React App with Jest

Author Aman Thakur
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Jest is a beautiful testing framework that focuses on simplicity. You can install it using any of the following package managers: npm or yarn. It fits into the broader category of utilities named as test runners. It works great for testing React applications. To get started with Jest, you can follow this introductory article: Getting Started with Jest.

This article will discuss various testing methodologies in the React framework using Jest such as Snapshot testing and Mock Testing.

Jest Setup for Snapshot Testing

If you are new to react apps, we recommend using Create React App. Firstly, you will only need to add react-test-renderer for rendering snapshots. 
Run,

yarn add --dev react-test-renderer

Or 

npm install react-test-renderer --save-dev

After this command, the library will successfully be added to the node_modules as a dev dependency.

Now let's start writing our first test for our simple React component. Let us name it Link.js in the src directory and define a class-based React component named Link.

Link.js

import React from "react";


// created a class named Link which inherits React.Component
// and been exported as module to be tested
export default class Link extends React.Component {
constructor() {
  super();
   
   // defining the state these state depend upon program 
   // workflow and can be modified as our component get 
   // updated
  this.state = {
    class: "normal",
    welcomeMessage: "Welcome to Coding Ninjas!",
  };
}

render() {
  return (
    <div>
      <a className={this.state.class} href={this.props.page || "#"}>
        {this.props.page}
      </a>
      {this.state.welcomeMessage}
    </div>
  );
}
}
You can also try this code with Online Javascript Compiler
Run Code

 

The file structure will look as follows:

 

Let's write our first snapshot test, Add a new file to our src directory named Link.test.js, and write down the following code given below:

Link.test.js

import React from "react";
import Link from "./Link";
import renderer from "react-test-renderer";


// defining the tests with description and also defining the
// page which it is directed to so that it keep a snap of it
// if the link get changed it will throw an error
it("renders correctly", () => {
const tree = renderer
  .create(<Link page="www.codingninjas.com" />)
  .toJSON();
console.log(tree); // log out the JSON object for the component within Link
expect(tree).toMatchSnapshot();
});
You can also try this code with Online Javascript Compiler
Run Code


The file structure will look as follows:


 Now run the command given below to test our application finally,

yarn test


You will find that a folder named __snapshot__ will be created in the src directory, which will contain the file named Link.test.js.snap that will be reused during the subsequent test execution. The content of the folder will look as follows:


This is what the console output looks like after the test.

Output


Let's test whether our snapshot test works or not. For that, just change the highlighted line in Link.test.js as follows:

Link.test.js

import React from "react";
import Link from "./Link";
import renderer from "react-test-renderer";

it("renders correctly", () => {
const tree = renderer
  .create(<Link page="www.codingninja.com" />) // removed the s 
  .toJSON();
console.log(tree);
expect(tree).toMatchSnapshot();
});
You can also try this code with Online Javascript Compiler
Run Code


Now run the same command yarn test or npm test in the terminal again; you will receive that the test failed and output as follows:


Now let's assume that you want to update to the latest snapshot. You can use the command yarn test -u  and the test case passed, and the snapshot will be updated accordingly.

Jest Setup for Mock Testing

In this section, we will discuss about usage of Jest mock numerous ways such as,

  • Mocking up the entire React Component.
  • Mocking up single and multiple functions is not specific to any Javascript development framework. We can still use Jest to plain old javascript files containing functions.
  • Mocking API calls used inside Javascript functions or Javascript code, i.e., we can use Jest to mock up third-party integration.

Mocking React Component

React apps are generally composed of various components depending upon each other. To get the simple idea about React Components, i.e., not more than presentation and logic.

Like any complex system built using OOP is composed of many components in the same way the React App is a collection of components. When we are testing a component, we need to ensure that the component under test depends on two other components that need to be moved up to avoid failures and independently test the component.

Let’s start testing up our React component by creating mock components.

Create a folder named components. 

Create 3 file named component1.jscomponent2.js and component3.js and write the respective code given below:
component1.js


import React, { Component } from "react";

// created a component1 class 
class Component1 extends Component {
render() {
  return <div id="component1"> Hello Component1 </div>;
}
}

// exporting it as a module
export default Component1;
component2.js
import React, { Component } from "react";

// created component2 class
class Component2 extends Component {
render() {
  return <div id="component2"> Hello Component2 </div>;
}
}

// exporting component 2 class
export default Component2;
You can also try this code with Online Javascript Compiler
Run Code

component3.js

import React, { Component } from "react";
import Component1 from "./component1";
import Component2 from "./component2";


// created component3 class which includes component1 and component2
// as its dependent component
class Component3 extends Component {
render() {
  return (
    <div>
      <div id="component3">Hello Component3</div>
      <Component1 />
      <Component2 />
    </div>
  );
}
}


// exporting the component3
export default Component3;
You can also try this code with Online Javascript Compiler
Run Code

From the above, we can see that Component3.js basically depends on Component1.js and Component2.js.  The directory structure of the project is as follows

From the above picture, you can see that there is also a test folder that contains the code to test component3 and mock-up component1 and component2.

component3.test.js

import React, {Component} from 'react'
import {render, container} from '@testing-library/react'
import Component3 from '../components/component3'
// arrange - mock setup


// mocking component1
jest.mock('../components/component1', () => () => <div id="mockComponent1">Hello Mock Component1</div>)


// mocking compoent2 
jest.mock('../components/component2', () => () => <div id="mockComponent2">Hello Mock Component2</div>)


// describe defines the test suit with 
// defined predefined test cases
describe("mock component tests", () => {
  test("mocked components in react", () => {
      // act
      const {container} = render(<Component3 />)
      // assert
      console.log(container.outerHTML)
      const mockComponent2 = container.querySelector('div#mockComponent1')
      const mockComponent3 = container.querySelector('div#mockComponent2')
      expect(mockComponent2).toBeInTheDocument()
      expect(mockComponent3).toBeInTheDocument()
  })
})
You can also try this code with Online Javascript Compiler
Run Code

toBeInTheDocument()'  is the matcher which looks for the given HTML Element in the HTML document created by React.

Now run the command given below to test the application component3 using mock components. 
yarn test src/tests/component3.test.js

Mocking Function using Jest

Let’s start mocking functions in jest i.e, creating stub functions in Jest.

Firstly create a project named “jest-mockfunctions”.

Now, run

cd  jest-mockfunctions

Run the command,

yarn init

Now, install jest

yarn add --dev jest

In package.json add scripts tag and attach the following test command to it, which is highlighted and given below:

Package.json

{
 "name": "jest-mockfunctions",
"version": "1.0.0",
"description": "for mock functions",
"main": "index.js",
"scripts": {
  "test": "jest --watchAll"
},
"author": "aman-thakur",
"license": "MIT"
}

Create an src directory and a subdirectory named test. Add the following code to the file named app.js and app.test.js in the test directory, respectively.

app.js

// define a function to return full name
function getFullName(firstname, lastname) {
    return firstname + " " + lastname;
}


// define a greet function
function greet(firstname, lastname) {
    return "Hello! " + this.getFullName(firstname, lastname);
}


// export the function as module
module.exports = { getFullName, greet };
test/app.test.js
// describing the test suite for the spyOn 
// funcitons
describe('illustrate mocks and spies', () => {
test("illustrate spies", () => {
  // arrange
  const greeter = require("../app.js");
  const greeterSpy = jest.spyOn(greeter, 'getFullName');
    
   // act
  const result = greeter.greet("aman", "thakur");
   
   // assert
  console.log(result);
  expect(greeterSpy).toHaveBeenCalled();
  expect(greeterSpy).toHaveBeenCalledWith("aman", "thakur");
});

test("illustrate mocks", () => {
  // arrange
  const mock = jest.fn().mockReturnValue("mocked name");
  const greeter = require("../app.js");
  greeter.getFullName = mock;
    // act
  const result = greeter.greet("aman", "thakur");
    // assert
  console.log(result);
  expect(result).toBe("Hello! mocked name");
  expect(mock).toHaveBeenCalled();
  expect(mock).toHaveBeenCalledTimes(1);
  expect(mock).toHaveBeenCalledWith("aman", "thakur");
});
});
You can also try this code with Online Javascript Compiler
Run Code

We can use the Jest matchers to validate the mock as shown below.

  • toHaveBeenCalled():  Validates if the mock was called.
  • toHaveBeenCalledWith(arg1, arg2):  Validates if the mock was called with the given arguments.
  • toHaveBeenCalledTimes(n): Validates the number of times the Mock would have been called.

 

After executing the terminal will look like as follows:

Mocking External APIs using Jest:

Before mocking external apis using jest, there are a couple of reasons you should avoid calling external endpoints every time when the test is runned.

  • It might involve cost
  • You can’t control the response neither test all the expected response nor errors
  • It might not always be available.

Although we can see how we can mock APIs using jest framework.

Create a project and initialise it with yarn or npm only just moved into the terminal and write the command

yarn add --dev jest axios

Now create a new file in src directory app.js and a subdirectory named test with file name app.test.js

Inside app.js write the code given below:

app.js

const axios = require('axios');


// axios is the 3rd party package to perform 
// network request to get the JSON response from 
// the link https://reqres.in/api/users/2

function getUserData() {
axios
  .get("https://reqres.in/api/users/2") 
  .then((response) => console.log(response.data)) // print the data
  .catch((error) => console.log(error)); // print if error get generated
}

module.exports = {getUserData}
You can also try this code with Online Javascript Compiler
Run Code


Inside app.test.js, write down the code given below.

app.test.js

const axios = require("axios");
jest.mock("axios");


// mocking up the api calls 
// and defining the test suits for mocking apis
describe("mock api calls", () => {
 
   test("mocking external endpoint in axios", () => {
   
   // arrange
  const mockedResponse = {data: { username: "test-user",address: "India" }};
  axios.get.mockResolvedValue(mockedResponse);
  const app = require("../app.js");

  // act
  app.getUserData();

  // asserts
  expect(axios.get).toHaveBeenCalled();
                                              expect(axios.get).toHaveBeenCalledWith("https://reqres.in/api/usrs/2");
});
});
You can also try this code with Online Javascript Compiler
Run Code

Now finally run the test command 

yarn test 

your output will be as follows:


FAQs

  1. What is snapshot testing used for in React?
    Snapshot testing ensures that the UI of the website does not change unexpectedly. It allows rendering React components as pure Javascript functions.
     
  2. Where to put Jest test?
    It is considered the best practice to put all your test files in ./test inside ./src directory
     
  3. Which library is used for snapshot testing?
    Jest has an interesting feature called snapshot testing, which aims to test Javascript objects. It works nicely with React components since you can examine the DOM output and produce a "snapshot" at runtime as you render a component.
     
  4. Is snapshot testing worth it?
    Snapshot tests are a great way to ensure that your user interface doesn't alter abruptly. A basic snapshot test scenario renders a user interface component, takes a snapshot, and compares it to a reference snapshot file kept with the test.

Key Takeaways

This article primarily discusses snapshot testing and mock testing which are done during software development lifecycle. Testing-driven development always adds a cherry on the cake to ensure that the product you are developing is secure and reliable.

Hence never stop your journey of learning. Here are some of the links where might be interested in such as Getting started with JestMocking in JestMatchers in Jest.

Happy Learning!

Live masterclass