React testing Library

 Reynaldo Rodríguez
Reynaldo Rodríguez
December 19, 2023
React
Redux
Jest
React testing Library

Software testing is all about gaining confidence: When we're doing changes in our application, we don't want things to break.

So, what can we do to prevent production failures?

Well, we run our app and go throw the critical paths trying to find any new bug introduced by our changes. This could be really tedious work, but here is where automated testing could save us some time.


Today we are focusing on unit testing. We'll be testing separate chunks of code and we’ll do it keeping our test as close to the way a final user would use our app as possible.

Some tips:

- Don't focus on the implementation details of what you're testing.
- Try to keep the automated testing as close as possible to the way the user will interact with our components.
- Think how you would test your app if you were a manual tester.

Ok let's go:

To get this we are going to use React testing library (it comes ready to go with your create-react-app)

React testing library provides us a `render` function that allows us to render a component. It’s super straightforward, you just need to call the `render` function with the component you’d like to test, and that’s it.

We are also importing `screen`, which helps us to validate that the UI looks the way it should.


It's important to render the component before starting to use screen methods. With screen.debug we get the React Node of the element printed on our terminal, so we can see what’s being rendered by our test. This is super useful and time-saving.

Our first validation:

With our component rendered, we are ready to start our UI-based validations. Our sample app has a counter, and it must start at 0 when it’s rendered, so let’s make sure this is happening.

You can learn more about screen getters here:
https://testing-library.com/docs/queries/about/#screen

In this scenario we are using screen.getByText, which takes a string or regex to get the element we want.

`expect` is the way we assert the results of a test, it comes from the Jest testing framework (https://jestjs.io).

`toHaveTextContent` is part of jest-dom matchers, learn more:
https://github.com/testing-library/jest-dom

With those three lines, we just validated the initial state of our counter.

Now, let’s make sure it’s value increases and decreases when increase and decrease buttons are clicked.

Interacting with our components in the way a user would:

Here is where things get interesting: We’ll be using userEvent to simulate user interactions, such as clicks and keyboard strokes. We’ll be doing a basic usage of this but you can dive into its docs to check the full capabilities of userEvent:
https://github.com/testing-library/user-event

Let’s test the increment and decrement buttons.

The first thing we need to do is to use screen functions to get the `count` element, then we’ll need the `increment` and `decrement` buttons.

In this scenario we are using `screen.getByRole` (full description here), which takes the role of the element as first parameter and also takes an object as second parameter. We can use the name property of that object to query the elements of the given role.

Once we get the element, we’re using the `userEvent.click` function to click our elements, `userEvent.click` takes the element we’d like to click as its first parameter.

In the above test, we tested the functionality of the counter, without minding how the counter is implemented- we don’t care, the same way the final user won’t. This way we get a future-proof test decoupled from the implementation details.

Jest mock functions:

Next, we're using userEvent to fill some inputs on our Form component, but first, we’ll need to give a simple intro into Jest mock functions.

Basically, it is a function that allows us to expect a bunch of different things like the parameters the function was called with and the number of times the function was called.

Read more on the Jest docs. The syntax to declare a Jest mock function is:

Testing our forms:

First we define our test data (`randomUser`), then we define a submit handler Jest mock function, and we pass it to Form’s props (just as we do when using the Form component). For this test we’re using `screen.getByLabel` to get our inputs, and `screen.getByRole` to get the send button.

To fill our inputs, we have userEvent.type, which takes as its first parameter the element we’d like to type on and the string we’d like to type as the second one.

To sum up, we just filled the inputs, we hit the send button and we checked that the handleSubmit function was called with the right data. We also checked that the function was called once.

How can we deal with provider-dependent components? (Redux, ContextAPI).

Sometimes our components need a wrapper that provides its context. Gracefully, `render` function takes an options object as its second parameter and as you may be guessing: Yes, you can pass a wrapper as a render option.

First, let’s create a `test-utils.js` file:

We just created our `reduxRender` function, and it’s ready to be used. But first, let’s do the same for a React ContextAPI example:

Just to show that the tests are actually the same, no matter if it's the Redux one or the ContextAPI one, we create our validateCounter function. We just need to call the respective render for each component, and call `validateCounter` with its initial value:


What if we need to interact with APIs?

Here is where MSW joins the party. Sometimes we need to test how our components integrate with external APIS. Luckily we have MSW; a full set of API mocking tools that intersects requests on the network level. We'll be covering just a few of them, specifically `rest` and `setupServer`. You can have a look on MSW: https://mswjs.io/

First we need to set up our mocking server:


Alright, we are done with the server setup, now let’s write some tests.

Happy path:

Unhappy path:

Thanks for reading!

That’s all for now: we covered some simple scenarios, the main idea of this blog is to show how simple it could be to start doing some automated testing with this powerful tool. I strongly recommend going through the docs to have a look at the full capabilities that React Testing Library provides.

Also, I recommend having a look at Kent’s blog for more useful information on how to improve our testing, JavaScript and React skills: https://kentcdodds.com/blog/

Last but not least, here is a link to my sample repo for the tests we did. Please feel free to submit an issue on anything you think could be improved (or maybe a PR if you’d like to) https://github.com/facundop3/testing-react-workshop

Don't miss a thing, subscribe to our monthly Newsletter!

Thanks for subscribing!
Oops! Something went wrong while submitting the form.

Introduction to Redux Toolkit + RTK Query

Redux has long been the go-to library for managing global state in React applications. However, with time, the popularity of Redux fell due to the complexity of configuring a store and also the fact that Redux requires too much boilerplate code. In this article, we will go into how Redux Toolkit solves these problems.

October 18, 2022
Read more ->
React
Redux

Artificial intelligence into a react application

Artificial Intelligence (AI) is a type of software that is capable of performing tasks that require human intelligence and judgement. Tensorflow is a library used to access AI models for use on the browser.

January 18, 2023
Read more ->
Artificial intelligence
React
Tutorial

Contact

Ready to get started?
Use the form or give us a call to meet our team and discuss your project and business goals.
We can’t wait to meet you!

Write to us!
info@vairix.com

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.