Test your Components With React Testing Library

So far, you’ve learned how to do simple unit testing to test simple functions. But what aboutĀ  component behavior? How canĀ you check that the user is seeing whatĀ you want them to with no regression?

In other words, how doĀ youĀ test components? šŸ™ˆ

As you saw in the last chapter, testing works by running tests and comparing what you get with what you expected. However, React components supply instructions for updating the DOM. This means that to test components, you need to carry out a render, check the generated DOM, and compare that with what you expected.Ā 

To do this,Ā you can use React Testing Library. šŸš€

Discover React Testing Library

React Testing Library gives you access to tools located on Ā react-domĀ  and Ā react-dom/test-utilsĀ  that help youĀ follow best testing practice and receive readable error messages.

This solution does not replace Jest but worksĀ alongsideĀ it. React Testing Library lets you focus on the DOM by recreating it, mocking interactions, and checking the render. It helps you toĀ step into your end users’ shoesĀ and anticipate what they will see.Ā 

For example, when you want to test a component that makes an API call, you don’t necessarily need to check the Ā useEffectĀ  and Ā stateĀ  that enable you to do all of that. Instead, React Testing Library’s logic checks that you have your component, it’s replaced with a loader while the data loads, and it’s furnished with the data you’re fetching.Ā Ā 

DoĀ I have to worry about integration or unit testing here?

Well, React Testing Library lets you do both. You can test your hooks in isolation for unit testing and test interactions between different components, thereby carrying out integration testing.Ā 

Let’s test components with React Testing Library!

Create a Simple Component Test

Don't we have to install the library?Ā 

No need! React Testing Library is now one of the basic tools installed with Create React App. You just have toĀ import whatĀ you need into your test file.

We’ll start by testingĀ theĀ Footer component for switching theme. In Ā /components/FooterĀ  ,Ā  create an Ā index.test.jsĀ  file.

First of all, let’s check that FooterĀ  rendersĀ without crashing. To do this, import Ā FooterĀ  , the Ā renderĀ  from React Testing Library, and use Ā renderĀ  :

import Footer from './'
import { render } from '@testing-library/react'

describe('Footer', () => {
   test('Should render without crash', async () => {
      render(<Footer />
   })
})

If you haven’t quit watch mode, your tests will run automatically. Otherwise, redo Ā yarn run testĀ  . And there is an error.

TypeError: Cannot destructure property toggleTheme of '(0 , _react.useContext)(...)' as it is undefined.

Of course! This component is one of a group that uses the context. But here, component is not wrapped by provider for the Ā lightĀ  /Ā  darkĀ  theme . šŸ¤¦ā€ā™€ļø

As you can imagine, React Testing Library has a way of managing all this. We'll look at a cleaner way of doing this later, but for now,Ā wrap the Ā  FooterĀ  component withĀ  ThemeProviderĀ  directly in the test:

import Footer from './'
import { render } from '@testing-library/react'
import { ThemeProvider } from '../../utils/context'

describe('Footer', () => {
   test('Should render without crashing', async () => {
      render(
         <ThemeProvider>
            <Footer />
         </ThemeProvider>
      )
   })
})

Bravo! Now the test return is all green. āœ…

Let’s see what elseĀ you can test in a component.

Test Component Events

React Testing Library helps you anticipate your end-user experience.

How can we testĀ if theĀ Ā NightModeButtonĀ  works properly?

We’re not going to check the context’s internal state. Instead,Ā let’s look at what the user sees.

The button displays ā€œā˜€ļøļøā€ in day mode and ā€œšŸŒ™ā€ for night mode. We need to check that this is what is being displayed.

So let’s get the button content and compare the text displayed.

Interact With an Element

The library contains a series of selectors that give you access to a specific element (like in JavaScript). Look over the React Testing Library documentation to learn about all of the selectors you can access.Ā 

You can select an element by its role, label, placeholder, etc. Our Ā FooterĀ  only contains a single button, so you can useĀ Ā getByRoleĀ  .

You also need Ā screenĀ  , which you import withĀ  Ā renderĀ  :

import { render, screen } from '@testing-library/react'

What’s Ā screenĀ ?

screenĀ  is like the Ā bodyĀ  that contains the component, from which you can use your selectors.

The followingĀ accesses the button:

test('Change theme', async () => {
   render(
      <ThemeProvider>
      <Footer />
      </ThemeProvider>
   )
   const nightModeButton = screen.getByRole('button')
})

And from here on, things start to get serious! šŸ‘©ā€šŸ’»šŸ‘Øā€šŸ’»

Like with the test from the last chapter, we’re going to compare what we expect with what actually happens.Ā 

To begin with, the theme's initial valueĀ lightĀ  : "ā˜€ļøļø" is displayed. WhenĀ you click on the button, the value of the theme changes (with Ā toggleThemeĀ  ), and the theme becomes Ā darkĀ  . The button now displays "šŸŒ™". A good test is to do the following:

1- Check thatĀ you have "ā˜€ļøļø".

2- Click on the button.

3- Check that you get "šŸŒ™".

Let’s start with the first stage, checking forĀ "ā˜€ļøļø" :

test('Change theme', async () => {
   render(
      <ThemeProvider>
         <Footer />
      </ThemeProvider>
   )
   const nightModeButton = screen.getByRole('button')
   expect(nightModeButton.textContent).toBe('Switch mode : ā˜€ļøļø')
})

Looking at the terminal, you see that the test works. Yay!

Now it's time to move onto stage 2 and then run straight into stage 3, which looks a lot like stage 1.

To interact with the component, you need Ā fireEventĀ , which you use to trigger the DOM eventsĀ (in this case,Ā Ā clickĀ ) . Therefore, you do the following:

import { render, screen, fireEvent } from '@testing-library/react'
import { ThemeProvider } from '../../utils/context'
import Footer from './'

test('Change theme', async () => {
   render(
      <ThemeProvider>
         <Footer />
      </ThemeProvider>
   )
   const nightModeButton = screen.getByRole('button')
expect(nightModeButton.textContent).toBe('Switch mode : ā˜€ļø')
fireEvent.click(nightModeButton)
expect(nightModeButton.textContent).toBe('Switch mode : šŸŒ™')
})

Bravo! You’ve just successfully tested your Ā FooterĀ  component!

Check out a few additional testing methods in the screencast below šŸ‘‡:

Test Your Hooks

In part 2, you learned how to create your own custom hooks. But how would you go about testing them? āš“ļø

It might be tempting to test them independently, but most of the time, this is not in line with the React Testing Library philosophy. Indeed, this approach could be considered ā€œtesting implementation details.ā€ It takes up time but is not relevant, which is what you want to avoid.

In any case, you’veĀ already tested one of your hooksĀ without even realizing it.Ā 

Go ahead – launch the commandĀ  Ā yarn test -- --coverageĀ  Ā  to see.

A screenshot of your coverage
A screenshot of your coverage

As you can see, your Ā utils/hooks/index.jsxĀ  file has been tested (the percentage is low because the Ā useFetchĀ  hook in the same file hasn’t been tested). This is because yourĀ  FooterĀ  component uses the hook useThemeĀ to access Ā themeĀ  and Ā toggleThemeĀ  . Most of the time, this is the best method when testing hooks.Ā 

The main lesson to take away is that the best method to test a hook is to test a component that uses this hook.

Give It a Go!

It’s time to put everything you’ve learned in this chapter into practice. As usual, you can start the exercise on branchĀ P3C2-begin.

screenshot of the new function that allows a user to a favorite
This is what the new function for adding a favorite looks like

This is what the new function for adding a favorite looks like

You should do the following:

  • Create a test file for Ā CardĀ  .Ā 

  • Check that Card is using the Ā pictureĀ  that you passed as a prop.

  • When you pass a Ā titleĀ  prop, test whetherĀ  it displays correctly.

  • Check that the title changes when a profile is selected as a favorite (to do this, you can use the Ā closestĀ  method – refer to the documentation – which will give you access to the Ā closest parent Ā divĀ  )Ā Ā  .

You can find the solution on branch P3C2-solution.

Let’s Recap!

  • React Testing Library is a solution which lets you test React components and can be used alongside Jest.Ā 

  • You don’t need to test every component detail (no need to test your hooks individually or the internal state), but instead try to put yourself in the user's place.Ā 

  • renderĀ  lets you generate your element by simulating the behavior of the navigator.Ā 

  • screenĀ  gives you access to selectors to test your components.Ā 

What did you think of React Testing Library? Not bad, is it? In the next chapter, we’ll keep using it to test our components that make API calls. See you there! šŸš€

Ever considered an OpenClassrooms diploma?
  • Up to 100% of your training program funded
  • Flexible start date
  • Career-focused projects
  • Individual mentoring
Find the training program and funding option that suits you best