Testing React apps with React Testing Library — An Intro

Nishant Sharma
TestVagrant
Published in
5 min readMay 24, 2023

--

Introduction

React Testing Library (RTL) is a popular testing library for React applications that emphasizes testing your components from the perspective of the end-user. It provides a simple and intuitive API for testing your components that doesn’t rely on implementation details or testing implementation details.

The basic idea behind RTL is to

  • simulate user interactions with your components and assert that they behave as expected.
  • Instead of testing individual functions or methods in isolation, you test your entire component as it would be used in the actual application.
  • This makes your tests more realistic and helps ensure that your components are working as expected in the context of the application.

Let’s start with a test!

  • Create a react app
npx create-react-app color-button-app

This will create a react application with…

  • Configuration
  • Webpack and Babel
  • Web Server
  • Testing Library!

We will also be using npx with create-react-app which in turns…

  • Downloads the latest version of create-react-app templates every time.
  • Not dependent on when you last installed create-react-app

By default there will be a test present inside a spec.js which will look something like this

Now this test will

  • renders the App component, which means it will creates a virtual DOM.
  • uses the screen function to query for an element that contains the text "learn react" (case-insensitive) within the rendered component. It then assigns this element to a variable named linkElement.
  • uses the expect function to assert that the linkElement is in the document. If it is not, the test will fail.
  • Overall, this test case checks if the App component renders with a link that contains the text "learn react".

Jest and Jest-DOM assertions

RTL uses jest for assertions. These assertions determines whether the tests fails or passes. Below are the some common examples of jest assertions used with react.

  1. expect(element).toBeInTheDocument(): This assertion verifies that the given element is present in the document. This is often used to verify that a React component is rendered correctly.
  2. expect(element).toHaveAttribute(name, value?): This assertion verifies that the given element has the specified attribute with an optional value. This is often used to verify that a component has the expected props or attributes.
  3. expect(fn).toHaveBeenCalled(): This assertion verifies that the given function has been called. This is often used to verify that a callback function has been called in response to a user interaction.
  4. expect(fn).toHaveBeenCalledWith(...args): This assertion verifies that the given function has been called with the specified arguments. This is often used to verify that a callback function has been called with the expected data.

You can find more information on the Jest documentation website: https://jestjs.io/docs/en/expect

How Jest is different from React-test-library?

React Testing Library helps with

  • Rendering components into virtual DOM ( rendercomponent)
  • Searching virtual DOM ( getByText() method)
  • Interacting with virtual DOM (i.e; clicking the button)

RTL needs a test runner (Jest) which will

  • Find tests, run them, make assertions, this is where Jest comes into the picture. Jest is not the only runner. We have mocha, jasmine, etc.
  • Jest is recommended by Testing Library
  • comes with create-react-app

Note: Jest is needed for asserting the RTL tests

npm test → runs an npm script that runs Jest in watch mode

Jest Watch Mode

  • Watch for changes in the files since the last commit
  • Only run tests related to these files
  • No changes? No tests
    - Type a to run all the tests

In simple terms Jest when running in watch mode will only execute the tests if there is a change in the current test file, if not jest will not run the tests.

Jest watch when there is no change since the last commit
Jest in watch mode when there is no change since the last commit to the current file

And as soon as there is a change in the current Jest will start executing the test.

What are Jest dom assertions?

  • jest-dom is an extension library for Jest that provides additional matchers (assertions) for DOM testing. It enhances the readability and maintainability of your tests by providing more intuitive and descriptive error messages when assertions fail.
  • jest-dom includes a set of custom matchers for common DOM operations like querying for elements, asserting their content and attributes, and simulating user events like clicking, typing, etc.
  • Here are a few examples of jest-dom matchers:
  1. toBeVisible: Checks if the element is visible on the page, meaning it is not hidden with CSS or due to the parent element's display property.
  2. toHaveTextContent: Checks if the element has the specified text content.
  3. toHaveAttribute: Checks if the element has the specified attribute with an optional value.
  4. toHaveStyle: Checks if the element has the specified CSS style property and value.

To use jest-dom, you'll need to install it and import it in your test files. You can find more information and documentation on the GitHub repository: https://github.com/testing-library/jest-dom

Types of tests:

  • Unit Tests:
    - Test one unit of code in insolation, mostly a single function or a react component.
  • Integration Tests:
    - How multiple unit works together, testing the interaction b/w two components, services, etc.
  • Functional Tests:
    - Tests a particular function of software, testing the behaviour of the application and not testing the code itself.
  • End-to-end (E2E) Tests:
    - Uses actual browser and server (cypress, Selenium).

So which type of tests does RTL encourages us to test? Well its Functional tests, where we want to test functional/behavioural aspect of the application, rather the code.

Accessibility and Finding Elements in RTL

  • Testing Library recommends finding elements by accessibility handles, and here is the guide from RTL just to understand which query to use: About Queries | Testing Library (testing-library.com)
  • create-react-app’s example test uses getByText , which is OK for non-interactive elements, but there is a better way to do the same.
  • getByRole will let you locate your elements. example:

and here is documentation to figure out which role to look for Accessible Rich Internet Applications (WAI-ARIA) 1.1 (w3.org).

  • Some elements have built-in roles, button has a buttonrole, a has a link role.
  • If your tests can’t find an element like a screen reader would? Then your app isn’t friendly to screen readers 😭

Stay tuned for the next part…

--

--

Nishant Sharma
TestVagrant

Currently learning everything, plays video games too.