Comprehensive Guide to Test React Application with React Testing Library and Jest: Step-by-Step Tutorial

Comprehensive Guide to Test React Application with React Testing Library and Jest:  Step-by-Step Tutorial

Testing is a crucial aspect of software development, ensuring that your React application works as intended and continues to do so even as you make changes. The combination of React Testing Library and Jest is a popular choice for testing React applications. This Blog is a comprehensive guide to testing a React application using React Testing Library and Jest.

Now Let's Quickly see, Type of Testing

In a React application, various types of testing are commonly employed to ensure its reliability, maintainability, and optimal performance. The primary types of testing for React applications include:

  • Unit Testing

  • Integration Testing

  • End to End Testing (E2E)

  • Functional Testing

  • Security Testing

But As a Front-End Developer, we are only concerned about Unit Testing and Integration Testing, as a Developer, An Organization expects you to Implement these two Testing.

Prerequisites

  • Node.js and npm: Ensure you have Node.js installed on your machine, as it comes with npm.

  • React Application: Have a React application set up and ready for testing.

Setup and Configurations

Now it's Time to configure our React application for writing incredible test cases.

  1. Install React Testing Library

     npm install -D @testing-library/react
    
  2. Install Jest

     npm install -D jest
    
  3. Jest is a JavaScript Testing Framework, so in order to make it work for React Application we need to Install and configure Babel to Trans-piles Reacts JSX so it can work with Jest Seamlessly.

     npm install -D babel-jest @babel/core @babel/preset-env @babel/preset-react
    
  4. Configure babel.config.js at root level of your project.

     module.exports = {
         presets: [
             ["@babel/preset-env", { targets: { node: "current" } }],
             ["@babel/preset-react", { runtime: "automatic" }],
         ],
     };
    

    \In Certain Scenarios, there might be a case that the Bundler like Parcel and Webpack comes with its own Babel Configuration, and this may cause conflict with ours and bundle configuration.

  5. Now It's Time to initialize Jest.

     npm init jest@latest
    

    It will ask some question you can answer as per you project, else you can use these.

    \> Would you like to use Jest when running "test" script in package.json? ... yes

    \> Would you like to use Typescript for the configuration file? ... no

    \> Choose the test environment that will be used for testing » JSDOM

    \> Do you want Jest to add coverage reports? ... yes

    \> Which provider should be used to instrument code for coverage? » babel.

    \> Automatically clear mock calls, instances, contexts and results before every test? ... yes

  6. Install JSDOM library, before downloading it let's see what is JSDOM?

    This is Browser Like Environment often used as the test environment for running unit and integration tests. When you write tests for React components using tools like Jest and React Testing Library, JSDOM provides a simulated DOM environment, allowing you to make assertions about how your components interact with the DOM in Isolation.

     npm install -D jest-environment-jsdom
    

    If you're using Jest 28 or later, jest-environment-jsdom package now must be installed separately.

  7. now install one more Library

    This Library is a companion for Jest and the Testing Library ecosystem, providing a set of utility functions and custom matchers to enhance your testing experience. It extends Jest's assertion capabilities, making it easier and more expressive to write assertions for your DOM-related tests.

     npm i -D @testing-library/jest-dom
    

Now we have Installed enough in Library and Configured couple of them.

Writing Test Cases in not Tough but configuring is.

Now it's time to write Test.

Make A folder Named __tests__ and define this folder anywhere in the Project and write all the tests name with test.js or spec.js as suffix, as they are same naming convention. example, suppose you are writing test cases for Header Component we will name it as Header.test.js or Header.spec.js

Each Test while Testing React App can be Divided into Three Parts:

  1. Render: Firstly, you need to render the component in JSDOM which provided Browser Like Simulation to Test our React Component in Isolation, In Order to do so React-testing-library provides render() function

  2. Querying: After Rendering the Component in JSDOM, then we query the document. This is Done by Screen Object which is also a part of

    React-Testing-Library. It Comes With multiple properties to query the document Efficiently. you can read more about Query properties.

  3. Assertion is the validation step: After querying, the next step is to verify whether the actual results match the expected results. Assertions are statements or conditions that must be true for the test case to pass. If the actual results deviate from the expected results, the test case fails, indicating a potential defect in the system.

UNIT TESTING

Now let's Double click on the Unit Testing, Unit testing is a software testing technique where individual units or components of a program are tested in isolation from the rest of the application. The goal is to verify that each unit of the software performs as designed. In the context of a React application, units are typically individual functions, methods, or components.

You Will Learn Unit Testing by writing two Test Cases. Similar to, as per the User Behavior.

  1. Check whether Contact Us button is Rendered Properly or Not on Header

  2. Clicking to the Login button and insuring that does it Changes to the Logout

TEST CASE 1:

import Header from "../Header";
import { render, screen } from "@testing-library/react";
import appStore from "../../utils/Redux/appStore";
import "@testing-library/jest-dom";

// Here describe has no Functional benefits, It is just use to Structure our
// Testcase Properly
describe("All Test Related to the Header",()=>{
    // writing our first TestCase
    // instead of writing 'test', I can Write "it" as well
    test("Should Render Contact Us Button",()=>{
        // this will render the component into the JSDOM
        // In the Header Component, I'm using React-Router-dom for 
        // Navigation and using Redux store to provide the data to the cart
        // so also need to wrap those component with Header component
        render(
            <BrowserRouter>
                <Provider store={appStore}>
                    <Header />
                </Provider>
            </BrowserRouter>
        );

        // Querying the document
        // here in Querying we have multiple ways to get element and
        // getByRole is one of many ways
        const headerButton = screen.getByRole("button", name:"Contact Us");
        // assertion 
        // Here "toBeInTheDocument" comes from the library called
        // @testing-library/jest-dom: a utility library that enhances the capabilities of Jest, 
        // a popular JavaScript testing framework. provides a set of custom Jest matchers 
        // and utility functions that are designed to work seamlessly with the Testing Library ecosystem. 
        // Testing Library encourages testing from the user's perspective, 
        // focusing on the actual behavior of the application rather than implementation details.
        // As the name suggest toBeInTheDocument() will check wheather is it render of the document.
        expect(headerButton).toBeInTheDocument();
    })
}

TESTCASE 2:

In This Test Case, we will Try to mimic the user Interaction, By clicking on the button

import Header from "../Header";
import { fireEvent, render, screen } from "@testing-library/react";
import { Provider } from "react-redux";
import appStore from "../../utils/Redux/appStore";
import { BrowserRouter } from "react-router-dom";
import "@testing-library/jest-dom"

// you can define test cases without describe keyword
it("should check the cart is render or not", () => {
    render(
         <BrowserRouter>
             <Provider store={appStore}>
                    <Header />
             </Provider>
         </BrowserRouter>
        );
    const LoginButton = screen.getByRole("button", { name: "Login" });
    // here click is many of the various event that we can perform 
    // you can check more event on react-testing-libary Docs
    // fireEvent is the JSDOM Api that provide lots of function to perform action
    fireEvent.click(LoginButton);

    const LogoutButton = screen.getByRole("button", { name: "Logout" });
    expect(LogoutButton).toBeInTheDocument();
});

Important thing to note here is 'it' is alias of 'test.'

Note: This Blog will teach overview about the Testing, going through these above-mentioned libraries is must

Assignment

Build this react component. and write Unit test for this. and test does two input box render on the screen(JSDOM)

Solution

describe("test cases for contact us page", () => {
     it("should render 2 input boxes", () => {
        // this is rendering
        render(<Contact />);
        // this is making query and searching searching for element
        const buttonName = screen.getAllByRole("textbox");
        // this is assertion
        expect(buttonName.length).toBe(2);
    });
});

Integration Testing

Integration testing in React Testing Library involves testing the interactions and integration between different components of a React application. The goal is to ensure that the components work together as expected and that the application behaves correctly as a whole. Integration tests often focus on scenarios where multiple components are rendered together, and their interactions are tested to verify that the application functions as intended.

In the context of React Testing Library, integration testing typically involves rendering a parent component that contains several child components and then asserting that the interactions between these components produce the desired outcomes. React Testing Library provides utilities and methods that facilitate writing integration tests in a way that closely resembles how users interact with the application.

In the Unit Testing, we only render the one component, but here in the Integration Testing, try to add Multiple components in the Render function and write test for you own Application.

Conclusion

In conclusion, diving into the world of testing with React Testing Library, Jest, and other related libraries is a journey that pays dividends in the long run. As developers, our commitment to writing comprehensive and effective tests not only safeguards our code against unforeseen issues but also fosters a culture of confidence and collaboration within our teams.

By leveraging React Testing Library, we emphasize testing from the user's perspective, reinforcing the principle that the end-user experience is paramount. The simplicity and accessibility of the library empower us to create tests that mirror real-world interactions, ensuring our components not only function correctly but also provide a seamless and intuitive experience for those engaging with our applications.

Jest, with its robust testing framework, serves as a cornerstone for testing React applications. Its intuitive syntax, powerful assertion library, and the ability to parallelize tests contribute to a swift and efficient testing process. Embracing Jest alongside React Testing Library equips us with the tools to validate our code's behavior comprehensively, whether it's through unit tests, integration tests, or end-to-end tests.

Moreover, the journey of testing is not just about finding and fixing bugs; it's about fostering a mindset of continuous improvement. Writing test cases encourages us to craft modular, maintainable, and resilient code, thereby elevating the overall quality of our software projects. As we embrace automated testing, we pave the way for smoother and more reliable development cycles, ultimately saving time and effort in the ever-evolving landscape of software engineering.

In essence, the combination of React Testing Library, Jest, and other testing tools is a potent recipe for building robust, user-centric, and maintainable React applications. As we continue to evolve in our understanding and implementation of testing practices, we contribute not only to the stability of our projects but also to the growth and success of the broader software development community. Happy testing!