We're Hiring

Getting started with React Testing Library

There are many benefits that developers can unlock by using React. Speed, reusability and interactivity are all right up there. One thing that doesn’t get as much attention however, is testability.

In days gone by, front-end teams didn’t really have the tools (and more often than not, the inclination) to properly test their code. With React, we now have some excellent testing tools at our disposal.

How we approach testing

At Kyan, our go-to testing framework is React Testing Library. Not only has it been recommended by the React team, but we’ve also bought into the entire philosophy behind it.  

Testing can be quite a daunting prospect if you haven’t had any experience with it before, which our front-end team certainly didn’t when we started. As we’ve learned the ropes, we’ve created our own set of principles and best practices to help us all get on board the testing train.

The philosophy behind React Testing Library

The principles that React Testing Library was built on were, to a large extent, a reaction to the libraries that came before. But “evolution over revolution” has produced an ethos of quality. The idea is to simulate user interaction and then test against the rendered output; the React Testing Library website sums this up nicely:

The more your tests resemble the way your software is used, the more confidence they can give you.

We’re looking to ensure our products work for the user, rather than testing whether our code works in a particular way.

This philosophy avoids testing implementations that become verbose and/or complicated, where developers might feel the need to change their code to create a passing test.

Testing use cases also allows developers to rethink entire implementations, and still be able to rely on their tests to tell them whether they’ve broken anything.

 

 

Setting your scope

Assuming you’ve decided on the tools you’re going to use, and you’ve done your first “hello world” test, you’re quickly going to run into the first question any developer asks when testing:

“What should I actually test?”

It can be difficult to know where to start and how far to take testing, but if in doubt, there’s a couple of ways to think about what you need to do. 

Whenever we start a piece of work at Kyan, we like to have a set of well-defined acceptance criteria. And if you’ve got that, you already know what your test cases are! And as a nice little bonus, this lends itself to thinking about testing use cases rather than code.

But in the event that you don’t have acceptance criteria to fall back on, think about this maxim from the brain behind React Testing Library, Kent C Dodds:

What part of this app would make me most upset if it were broken?

Keep it simple

In the past, one of the problems that I’ve found with testing is that it doesn’t always feel like productive work. You write a new feature, and suddenly find yourself grappling with a failing test that should be passing, doubling the amount of time that you spend on what should be a trivial piece of work.

This is one of those situations that can put novice testers off from learning the craft.

React Testing Library mitigates this to some extent by being easy to use and debug. But things necessarily get complicated sometimes, and when they do, it helps to try and remove complexity. There’s a few simple rules that we try to follow:

  • Write our tests in plain English

  • Maintain a common and easily understandable structure (more on this shortly)

 

 

Writing tests simply and using a common pattern helps us in the short-term; the less time we spend thinking about and writing tests, the more time we have for writing features. We’ve seen it help with upskilling as well; if developers with little testing experience can quickly grasp existing tests, they can take that knowledge into writing tests of their own.

It also helps our teams in the long-term. Tests, once they are written, likely won’t be looked at again until they fail. This is the point that they are most valuable, and the easier they are to read and parse, the more useful they are!

Building a structure

When writing tests we’ve found it useful to use a common pattern. It serves as a guideline for writing tests, but also helps us identify why tests fail. The general idea is to create a story that can read and quickly understand:

  • Setup: Create any mocks or test data

  • Render: Render your component

  • Interact: Exactly as a user would, interact with the rendered component, getting it into the state that you want to test

  • Assert: Write your expectations, testing against the changes that the end user would experience

 


  it('calls the click handler correctly', () => {
    const handlerMock = jest.fn();
    const props = {
      title: 'Hello world!',
      text: 'Lipsum...',
      buttonHandler: handlerMock,
    };

    render(<Panel {...props} />);

    userEvent.click(screen.getByRole('button'));

    expect(handlerMock).toHaveBeenCalled();
  });

 

We like to try and keep all of the information for a test within that test. The less a reader needs to traverse the codebase to figure out a test, the quicker they’ll be able to figure out (and fix) a failure.

With tests, there is no need to save bytes, or to abstract for the sake of abstraction. We’ve found that individual tests are far more useful when they contain all of the information needed to understand a failure.

There are exceptions to this rule, such as in cases of significant repetition or particularly long test files, but we generally try to avoid moving code for tests away from the place where it is used.

Conclusion

We’ve found that keeping the above in mind makes testing a much more pleasant experience for old hands and new hands alike. A huge part of our Kyan culture is not only discovering new ways of doing things (and our own way of doing things), but making it easier and more accessible for whoever joins tomorrow. 🐙

If you want to learn more about React Testing Library, I highly recommend the docs, which are very well written. For more on testing best practice, you can’t do much better than Kent C Dodd’s blog, particularly the following articles:

Common Mistakes with React Testing Library
Testing Implementation Details
How to Know What to Test

 

Previously from Dave:

Why do we love Next.js so much?
How do you solve a problem like caching in Progressive Web Apps?

 

We are Kyan, a technology agency powered by people.