There are many libraries available for React.JS testing. You would have probably heard about Jest, Enzyme, React Test Utils, React Testing Library, Dom Testing Library and many more. There are other libraries that help you assert in unit testing library like chai, expect, sinon.

In this tutorial, we are going to look into testing react.js applications using a library called React Testing Library.

Introduction to react-testing-library

React Testing Library logo

React Testing Library is a lightweight testing library aimed at providing good test practices. What are these best pratices? One of the rule for testing is that the unit tests should not be brittle. The unit tests should test the functonality of the components/function, and not its implementation. react-testing-library is meant to be replacement for enzyme, another popular testing library from Airbnb.

How react-testing-library helps write better tests?

Dom Testing Librray (which powers react-testing-libray) logo

react-testing-library is a wrapper on top of dom-testing-library. The primary goal of  dom-testing-library is to test just as your user use the application. Your users do not care how you are implementing the functionality, they care if it works as intended. By writing tests which closely resemble the way users use your system, you cut down on writing un-necessary tests and catch bugs faster.

react-testing-library also does not provide methods to test on the instance of the reactjs component. You only get the methods to test the dom, which resemble the way the user uses your application. Because you do not have methods to get instance of component, you do not write tests which test the implementation of component.

Getting started with react-testing-library

Install the library in your reactjs project using the command

npm install react-testing-library --save-dev

So you package.json should be updated with devDependencies with following "react-testing-library". At the time of writing this tutorial, the latest version of react-testing-library was 6.1.2, it might be different when you install the library.

"devDependencies": {
  ...
  "react-testing-library": "^6.1.2"
  ...
},

Writing the test

We are going to take an example of simple React component which has a button which increments number and displays it on screen. (If you have read other Techdomain tutorials, this example is our choice, but it is really simple to understand)

This is the example of App.js component

import React, { Component } from 'react';

export default class App extends Component {
  state = {
    number: 0
  }

  incrementNumber = () => {
    const { number } = this.state;
    this.setState({
      number: number + 1
    })
  }

  render() {
    const { number } = this.state;
    return (
      <div>
        <div data-testid="increment-number">
          {number}
        </div>
        <button data-testid="increment-button" onClick={this.incrementNumber}>
          Increment Number
</button>
      </div>
    )
  }
}

We are going to use two apis from react-testing-library

  • render - This method renders a React element into the DOM and returns utility functions for testing the component.
  • fireEvent - The `fireEvent` method allows you to fire events to simulate user actions.
import { render, fireEvent } from 'react-testing-library';

We will test the functionality of component - when the user clicks on the button, the updated number should be displayed on screen.

This is the test for the above functionality

import React from 'react';
import { render, fireEvent } from 'react-testing-library';
import App from './App';


describe('App Tests', () => {
  it('should increment number', async () => {

    const wrapper = render(<App />);
    let index = await wrapper.findByTestId('increment-number');
    expect(index.textContent).toEqual("0");

    fireEvent.click(wrapper.getByTestId('increment-button'))
    index = await wrapper.findByTestId('increment-number');
    expect(index.textContent).toEqual("1");
  })
})

We are using async function here because some of the methods of react-testing-library return promise (like findByTestId).

We get the instance of app using render function

  const wrapper = render(<App />);

Then we search for the DOM using the data-testid attribute for the number to check if it shows initial state as 0.

  let index = await wrapper.findByTestId('increment-number');
  expect(index.textContent).toEqual("0");

Using fireEvent, we fire a click event from the increment button.

  fireEvent.click(wrapper.getByTestId('increment-button'))

Then we test if the number on screen is incremented by 1

  index = await wrapper.findByTestId('increment-number');
  expect(index.textContent).toEqual("1");

Conclusion

Its very easy to get started with react-testing-library and write maintainable tests. To sum it up, using react-testing-library, you are going to save time writing un-necessary test, and write maintainable tests which do not break when someone change the functionality of component.

Did you find any typo or wrong information in the tutorial? If so, please mail to we[dot]techdoma[dot]in@gmail.com. Thankyou.