Max RozenTesting React

Learn Integration Testing with React Hook Form

Max Rozen
@RozenMD

Do you sometimes worry that your tests don't make sense? Struggling to get what people mean by "test from the user's perspective" and the classic piece of advice "test functionality, not implementation details"?

You're not alone!

I felt the same thing when I started using React Testing Library. I used to think of testing as just checks you had to do on individual components, directly asserting against props and state, and would struggle to think about how to test the integration of several components together.

What does "integration test" even mean?

It helps to think of integration testing like a bigger unit test, except the unit you're testing is the combination of several smaller components.

More concretely, instead of just testing a Button component, or a TextField component in isolation, we're going to test that they work when placed together into a form.

Let's get started!

We're going to be testing a form almost every public web app you're going to build has: a Login form. It's probably one of the most important parts of your app (in terms of business value), so let's be confident it actually works!

React Login Form

Setup

We're going to be using create-react-app, because it comes bundled with @testing-library/react. I'm also using react-hook-form to build our form, because it's the fastest way I know to build a form in React apps.

Steps

  1. Clone the repo

  2. Run:

    yarn start

    You should see something like this: React Login Form after starting

  3. At this point, if you ran yarn test, you would see the following:

PASS src/pages/Login.test.js
✓ integration test (177ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.134s
Ran all test suites.
Watch Usage: Press w to show more.

So how do we get here?

First off, here's the code from our integration test:

import React from 'react';
import { render, fireEvent, screen } from '@testing-library/react';
import user from '@testing-library/user-event';
import Login from './Login';
test('integration test', async () => {
const USER = 'some-username';
const PASS = 'some-pass';
render(<Login />);
const userInput = screen.getByLabelText(/username/i);
user.type(userInput, USER);
const passwordInput = screen.getByLabelText(/password/i);
user.type(passwordInput, PASS);
const submitButton = screen.getByText(/submit/i);
fireEvent.click(submitButton);
expect(await screen.findByText(/your username/i)).toBeInTheDocument();
expect(await screen.findByText(/your password/i)).toBeInTheDocument();
});

It might look like we're doing a few complicated things above, but essentially, we've taken the steps a user takes when logging in, and turned it into a test:

  1. Load the Login screen
  2. Click on the username input, and type the username
  3. Click on the password input, and type the password
  4. Click the Submit button
  5. Wait around for some sign that the Login worked

Some testing-library specific things worth calling out:

  • We import '@testing-library/user-event' to let us to type into our inputs
  • We import fireEvent from the '@testing-library/react' library to let us to click on our Button component
  • We've marked the test async to enable us to use findByText()
    • We use findByTest() after performing an action that may be asynchronous - like filling out a form. (findByText returns a Promise, letting us await until it finds the text it's looking for before continuing)

We've built a test that can type into our TextField components, click on our Button component, and trigger the Form component's onSubmit function, without ever referring to implementation details!

If you're confused about findByText vs getByText, don't worry - that's normal. In general though, findBy functions are for use after async actions (like clicking the Submit button), and getBy functions are for general use.

React Testing Library also has a cheatsheet with tips to help you decide which one to use.

Conclusion

You've just started to understand integration testing, but you best believe there's a lot more to it than this article!

If you want a more advanced perspective of integration testing your forms, I highly recommend reading the testing section of React Hook Form's Advanced Usage guide.

Wish there were more React testing examples on the internet?

Testing is one of the most important parts of coding, and getting a job. Yet you rarely see examples of how to actually do it. I'm writing a book that seeks to change that, by providing practical examples of React testing.

I'll send you updates, as well as useful articles based on the examples in the book. You can always unsubscribe.

    Join 81 React developers that signed up last month!