DEV Community

Cover image for Exploring the Basics of React Testing: A Journey into Rendering and Interaction
Iheanacho Ebere
Iheanacho Ebere

Posted on • Edited on

Exploring the Basics of React Testing: A Journey into Rendering and Interaction

When building a website and integrating diverse features, manual testing may appear viable at the outset. However, for larger projects, relying solely on manual testing becomes impractical prompting the need for the implementation of unit tests. Not only do unit tests enhance the integrity of your application, but they also provide a more scalable and efficient approach to ensuring the functionality of your codebase.

What is unit test?
Unit testing is a testing methodology that assesses individual software units in isolation. It involves scrutinizing the output of a function for any given input. This process ensures the verification of component rendering for specific inputs to React components.

In essence, writing unit tests is simply writing code to ascertain the code works as expected.

In this article we are going to be looking at the fundamentals of react unit testing ,exploring essential concepts and structures.

Both Jest and React Testing Library come pre-packaged with Create React App and adhere to the guiding principle that testing apps should resemble how the software will be used.

Prerequisties

  • Npm and knowlegde on node and javascript
  • Familiarity on react

In testing, the focus is on ensuring that your code performs as intended in comparing expected and actual outputs. The major aspects to test in your code include:

  • Rendering with or without props: Check if a component renders correctly with or without specific props.

  • Rendering with state changes: Test how a component renders when there are changes in its state.

  • Reacting to user interactions: Assess how a component responds to user interactions.

However, certain elements do not require testing:

  • Actual Implementation: We don't need to test the exact implementation, we just need to ensure component produces the expected output.

  • Third-Party Libraries: If utilizing third-party libraries like Material UI, there's no need to test them, as they are presumed to be well-tested.

In react unit testing , there's a conventional test block structure that is followed, which is :

  • Create a test block using either describe-it/test.
  • Inside the test block, the first thing we do is to render the component that we want to test.
  • Select the elements that we want to interact with queries.
  • Interact with those elements.
  • Assert that the results are as expected.

How To Setup Our Project

First create the react app with the create-react-app command. Since we'll be using Jest , its already pre-installed in your app.

npx create-react-app react-test-project

Ensure the following line is in the setupTests.js file:

import '@testing-library/jest-dom'
Enter fullscreen mode Exit fullscreen mode

How To Write Our First Test ?

Step 1: Create a component

Let’s create a component called Counter, that renders "Counting App".

import React, { useState } from "react";

const Counter = () => {

    return (
        <div>
            <p>Counting App</p>
        </div>
    );
};

export default Counter;

Enter fullscreen mode Exit fullscreen mode

Here, we just need to test if the Counter renders "Counting App". Now, where should we write the tests? We can write them inside files with .js suffix in “__ tests __” folders or files with “.test.js” suffix or files with “.spec.js” suffix anywhere inside our src folder and jest will pick it up.

Create a “counter.test.js” file inside the src folder and add the following code:

import Counter from "./counter";
import { render, screen } from "@testing-library/react";


describe("Counter Component", ()=> {
    it("should render counter component", ()=>{
        render(<Counter />)
        expect(screen.getByText(/counting app/i)).toBeInTheDocument()
    })
})
Enter fullscreen mode Exit fullscreen mode

Note: In order to let jest know about this test file, it’s important to use the extension .test.js.

The above test can be described as follows:

  • The “describe” block is employed to group together a set of tests under the overarching category of "Counter Component."
  • The “it” block is used to define individual tests within the describe block. Alternatively, the “test” block can also be used for the same purpose. Both methods take two parameters:
  • The first parameter names the test, such as "Render Counter Component."
  • The second parameter is a callback function, outlining the specifics of the actual test.
  • The render() method from the React Testing Library is utilized in the test to render the Counter component within a virtual DOM.
  • The screen property, offered by the React Testing Library, facilitates the selection of elements for testing based on the previously assigned test IDs.
  • The expect property is used to make assertions, comparing the actual results with the expected results.

With these foundational concepts in place, the testing process covers the basic rendering aspects. The subsequent step involves implementing counting functionality in the Counter component.

import React, { useState } from "react";

const Counter = () => {
    const [countValue, setCountValue] = useState(0);

    const increaseCount = () => {
        setCountValue((prevCount) => prevCount + 1);
    };

    const decreaseCount = () => {
        setCountValue((prevCount) => prevCount - 1);
    };

    return (
        <div>
            <h2>Counting App</h2>
            <button 
                data-testid="increase" 
                aria-label="Increase Count"
                onClick={increaseCount}
            >
                +
            </button>
            <p data-testid="count">{countValue}</p>
            <button  
                data-testid="decrease" 
                aria-label="Decrease Count"
                onClick={decreaseCount}
            >
                -
            </button>
        </div>
    );
};

export default Counter;
Enter fullscreen mode Exit fullscreen mode

This component that simply increases and decreases a numeric value at the click of respective buttons. Now our updated test file should look like this:

import Counter from "./counter";
import { fireEvent, render, screen } from "@testing-library/react";

describe("Counter Component", () => {
    it("should render counter component", () => {
        render(<Counter />)
        expect(screen.getByText(/counting app/i)).toBeInTheDocument()
    })

    it("should increment counter when increment btn is clicked", () => {
        // render the component on virtual dom
        render(<Counter />);

        //select the elements you want to interact with
        const counter = screen.getByTestId("count");
        //expect counter to initialize at 0.
        expect(counter).toHaveTextContent("0");
        //select increment btn
        const incrementBtn = screen.getByTestId("increase");

        //interact with those elements
        fireEvent.click(incrementBtn);

        //assert the expected result
        expect(counter).toHaveTextContent("1");
    })
})
Enter fullscreen mode Exit fullscreen mode

In the second test block, we are evaluating the rendering and increment functionality of the counter component. Here's a breakdown of the test:

  • Render the counter on the virtual DOM.
  • Utilize the screen property to select elements.
  • Set an expectation assertion to check if the counter initializes at 0.
  • Use the fireEvent function to simulate a click on the increment button.
  • The test asserts that the counter's text content changes and updates as expected.

Now after running the test, the result obtained can be seen below:

 PASS  src/counter/counter.test.js
  Counter Component
    √ should render counter component (39 ms)
    √ should increment counter when increment btn is clicked (22 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        4.188 s
Ran all test suites matching /counter/i.
Enter fullscreen mode Exit fullscreen mode

The assertions confirm that the Counter component not only renders as anticipated but also functions correctly when incrementing. I trust these tests have provided a foundational understanding of exploring basic rendering and interactive features within a React component using the React Testing Library. However, this marks just the initial phase of our testing journey ,as you continue your journey into the world of testing, the next step involves exploring more advanced techniques. My upcoming article Mocking Axios GET Requests, will dive deeper into the critical aspects of mocking and asynchronous testing. Make sure to follow along for a comprehensive understanding of these advanced testing concepts.

Stay focused, and happy testing!

References

Top comments (0)