Complete Guide to Unit Tests with React

Have you ever gotten yourself into a situation where a small change in the project was worrying because you didn’t know what could be broken? Well, I guess everybody passed through this at least once at some point. But what we didn’t know back there, i…


This content originally appeared on Bits and Pieces - Medium and was authored by César Felipe

Have you ever gotten yourself into a situation where a small change in the project was worrying because you didn’t know what could be broken? Well, I guess everybody passed through this at least once at some point. But what we didn’t know back there, is the existence of our best friend, Unit Tests. Unit Tests it’s a very important topic, no matter what technology do you use.

In this article, I want to dive into unit tests (only unit tests) on React Apps.

What’s unit tests?

Unit tests is a technique where you can test a unit — the smallest piece of code that can be logically isolated in an application. It can be a function, a class method, a subroutine, etc. In our case, we will test functions and React components most of the time.

Why unit testing?

As I said before, unit tests are our best friend. It gives to us confidence to make changes and refactors without worrying if our application it’s still working or not. In addition, it ensures to us that our code works properly, avoiding bugs and hours of debugging.

E.g.: There is a Link component that redirects internally to the SPA through to prop, then you added a new prop called href that redirects to external links like youtube.com

How do you ensure the to behavior is working normally, and you didn’t break existent flows? Going screen by screen and testing it? Ask for other develops checking their screens? No, you create a unit test that ensure that every time you click in a Link which has a to prop the navigation you be internally, and create another test for href behavior.

Before we practice, you need to know two important things: Jest and React Testing Library.

Jest

Jest is a JavaScript/TypeScript framework for testing, it runs the tests, check coverage, allow mocks and more. Jest is Awesome, if you don’t know yet, you must visit the docs after finishing this article.

React Testing Library

React Testing Library is a library that gives you superpowers to test your React Apps. Jest it’s framework-agnostic, it doesn’t care about which framework you use, so you need to use React Testing Library to handle react for us and made our life easier.

Let’s practice.

I’ll create a new React project using npx create-react-app unit-tests-tutorial --template typescript, create-react-app uses jest and react-testing-library by default, so we don’t need to do any configuration.

Now, let’s clear the project structure to remove unnecessary files.

New project structure

Testing UI Components

I created a simple button component that receive two props: label and onClick

So, let’s do two simple tests: check if the label is rendered and if onClick callback was called.

I want you to focus on the makeSut(SUT — System Under Test) function, I always use it in my tests, no matter if it is frontend or backend tests. When you centralize your actor (Button), it’s cleaner and easier to make changes on your tests, also it allows you to focus on the behavior you’re working on.

We have two magic functions from @testing-library/react that we need to learn:

  • The render function will render the component in a container and return some helpers like: getByText, getByTestId, getByRole, debug, unmount and more.
  • The fireEvent will dispatch an Event in the element we pass as argument, there are a lot of events, like: click, change, submit, blur, focus, etc.

These two function are the most important to us, we can fully test a component with them. There is the act function that is important too, but I’ll show later.

If we run the command yarn test, we will have the following result.

test result

Both tests are passing. We ensured that the two behaviors of our component are working correctly.

Now, let’s create a component a little more complex than a button.

The DropdownList component consumes the Button component and render a list of elements depending on the state, pretty simple. And that’s how it looks:

Dropdown list component

The nice part here, we added the Button component inside DropdownList, and we don’t need to care if works, all behavior wasproperly tested, and we know it will work. Now, let’s check what behavior this component has and test it.

Always focus on behavior instead of line coverage. You can end covering a line but not a behavior.

  • Check if list is hidden on initial render
  • Check if list is visible after one click on the button
  • Check if button labels are changing
  • Check if all items have been rendered correctly
  • Check if the remove callback is being called with correct values

So, let’s test it.

A few nice things:

  • The container prop return the HTMLElement of the container, so you can find elements and do all DOM manipulation you want, on the 3 first tests we used to find an element and use testing-library to check if is rendered on the DOM.
  • jest.fn function at the last test works as a spy, it knows if the function has been called, how many times was called, which parameters, and much more. It’s really nice to mock a dependency.

Again, we used makeSut function to prepare the actor (DropdownList) and make our test focused on behavior. If we run yarn test again, all tests are passing.

test results

Let’s create the App container that will consume the DropdownList component.

So, we have a component this component that do a fake api call and update the state to pass to the DropdownList. Let’s add a simple test to check if ul is rendered after clicking on the “Show Data” button.

Let’s run yarn test, and we will have a surprise.

test result with error

Our test is passing, but it’s logging an error. What we can do to fix it? Probably suppress error will work as well, but this time we need to fix the problem. So it happens because we have an asynchronous update of state in our component, so jest run the test and didn’t wait until the fakeApiCall runs and update the state, re-rendering the component.

Remember when I told about the act function? Well, it will save us now, wrapping the asynchronous action inside an act(() => { … }) block code, ensure that the test will wait until everything is done. So, let’s fix our test.

And that’s it, so simple, just adding act ensure that fakeApiCall will run, return data and the setState will re-render our component. Only after that, the button will be clicked. Running yarn test, everything it’s normal again.

test results

Testing Hooks

You’re probably thinking

Cool, but we are on React 18, we use a lot of hooks, how to test it?

It was kind of boring testing hooks, you needed to wrap the hook in a fake element, simulate the click of a button calling the function you need, and get the result. I hated it and react-testing-library hated it too, so they created a new library to help us called react-hooks-testing-library

Let’s install it yarn add -D @testing-library/react-hooks

Then, I’ll create the classic useCounter hook just as a simple example:

So, the useCounter hook has one state and two methods, how I’ll ensure that it’s working correctly?

Well, very simple, we use renderHook function to “render” our hook and return the state and the methods from it.

The render function is very nice, it accepts a provider in case your hook needs something like a context, also you can pass initial values to your hooks. All the values returned as inside a ref called result, renderHook also returns unomunt and rerender functions.

Basically, this is how we can test our hooks.

And that’s it, I hope you have enjoyed the content and learned something.

There is a lot more to talk about unit testing, like when you need to mock a dependency or spy it, but this can be another article. Comment if you want a part 2 focused on complex testing problems.

Build composable web applications

Don’t build web monoliths. Use Bit to create and compose decoupled software components — in your favourite frameworks like React or Node. Build scalable and modular applications with a powerful and enjoyable dev experience.

Bring your team to Bit Cloud to host and collaborate on components together, and speed up, scale, and standardize development as a team. Try composable frontends with a Design System or Micro Frontends, or explore the composable backend with serverside components.

Give it a try →

Learn more


Complete Guide to Unit Tests with React was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Bits and Pieces - Medium and was authored by César Felipe


Print Share Comment Cite Upload Translate Updates
APA

César Felipe | Sciencx (2022-05-03T15:30:54+00:00) Complete Guide to Unit Tests with React. Retrieved from https://www.scien.cx/2022/05/03/complete-guide-to-unit-tests-with-react/

MLA
" » Complete Guide to Unit Tests with React." César Felipe | Sciencx - Tuesday May 3, 2022, https://www.scien.cx/2022/05/03/complete-guide-to-unit-tests-with-react/
HARVARD
César Felipe | Sciencx Tuesday May 3, 2022 » Complete Guide to Unit Tests with React., viewed ,<https://www.scien.cx/2022/05/03/complete-guide-to-unit-tests-with-react/>
VANCOUVER
César Felipe | Sciencx - » Complete Guide to Unit Tests with React. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/05/03/complete-guide-to-unit-tests-with-react/
CHICAGO
" » Complete Guide to Unit Tests with React." César Felipe | Sciencx - Accessed . https://www.scien.cx/2022/05/03/complete-guide-to-unit-tests-with-react/
IEEE
" » Complete Guide to Unit Tests with React." César Felipe | Sciencx [Online]. Available: https://www.scien.cx/2022/05/03/complete-guide-to-unit-tests-with-react/. [Accessed: ]
rf:citation
» Complete Guide to Unit Tests with React | César Felipe | Sciencx | https://www.scien.cx/2022/05/03/complete-guide-to-unit-tests-with-react/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.