Testing React: A convert’s journey from Enzyme to Testing Library
Tags: testing, react
Published: 2022-06-02 22:34:53


<figcaption>Image by <a href="https://pixabay.com/users/wallace769-5217358/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=2264698" data-href="https://pixabay.com/users/wallace769-5217358/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=2264698" class="markup--anchor markup--figure-anchor" rel="noopener" target="_blank">Shri ram</a> from&nbsp;<a href="https://pixabay.com/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=2264698" data-href="https://pixabay.com/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=2264698" class="markup--anchor markup--figure-anchor" rel="noopener" target="_blank">Pixabay</a></figcaption>

---
I’m a big tester. Testing has saved my bacon enough times that I feel uneasy coding without it, like rock climbing without a rope. Even if I’m in a gym and the floor is really springy, a rope (like testing) helps minimize the damage when things inevitably go wrong.

When I started learning React several years ago, [Enzyme](https://enzymejs.github.io/enzyme/) was all the rage for test rendering and DOM manipulation. I come from an old-school back-end testing background (meticulous unit testing and isolation). Enzyme seemed great! I could take the same testing approach with React, testing state and other implementation details to my heart’s content.

Then I started hearing about Testing Library (specifically [testing-library/react](https://www.npmjs.com/package/@testing-library/react)). At first I was resistant: an opinionated library which enforced someone else’s ideas of “best practices”? My detailed unit testing approach was under threat! I steered clear.

As time went by, it became clear Testing Library was here to stay, so I thought I’d check it out. After trying it for one project (my [personal website](https://github.com/bonnie/bonniedotdev)), I am a total convert. Read on for my reasons why.

## Opinionated === Best Practices

Testing Library encourages your tests to interact with your code the same way your users would. For example: Find an element and click it. Then, instead of checking to see whether the *state* changed (sorry, not an easy option in Testing Library!), check to see whether the *page* changed in the way you expect.

This is known as testing *behavior* (what’s on the page) vs. testing *implementation* (internal state). After all, user experience determines whether your code is working according to spec — not what state happens to be.

The downside: when tests fail, there’s less granularity pointing to where exactly the tests failed (is the state the problem? Or is it something else in the onClick callback?). The upside: less test refactoring when your code changes. It’s a trade-off, but in front-end testing, I’m coming around to the “fewer, more robust tests” philosophy. The time spent tracking down errors is less significant than the time spent maintaining tests.

I’ve especially come to appreciate this in the past year or so as React has moved from class-based components to functional components with hooks. If the behavior doesn’t change from the user perspective, there should be little-to-no cause to update tests when updating the implementation. Trends in React will continue to evolve, and your app can evolve with them without requiring a major testing overhaul.

## Accessible Code

Another opinion from Testing Library: [how to find page elements](https://testing-library.com/docs/guide-which-query/) in your tests. The recommended element specifier is **role**, which relies on the [accessibility tree](https://developer.mozilla.org/en-US/docs/Glossary/Accessibility_tree) (aka how elements appear to screen readers and other accessibility tools). Using role to find page elements for tests makes sure you have accessibility at top-of-mind while creating your content.

You can also use Enzyme to find elements by role, but it is not nearly as easy: 1. You have to use the generic [find](https://enzymejs.github.io/enzyme/docs/api/ShallowWrapper/find.html) method to find role attributes

2. You have to account for cases for all attributes that represent role (for example, aria-role and role)

3. You have to account for inferred roles (like the “button” role for a <Button> element).

In Testing Library, you get all these role indicators for free with the *getByRole* method.

## jest-dom Assertions

Jest is pretty generic when it comes to [assertions](https://jestjs.io/docs/en/expect): You can test things like “does this variable have the right value?”, or “does this object have the expected property?”, or “was an error thrown?”, but there’s nothing specific to the DOM.

Testing Library’s [jest-dom](https://github.com/testing-library/jest-dom) to the rescue! Let’s say you want to know whether an element is visible on the page. You could use Enzyme to see whether the element [has the proper class](https://enzymejs.github.io/enzyme/docs/api/ShallowWrapper/hasClass.html), and use Jest’s `toBe`, like so:

```js
expect(myElement.toHaveClass('hiddenClass')).toBe(true);
```

Or, you could use jest-dom’s `[toBeVisible](https://github.com/testing-library/jest-dom#tobevisible)` :

```js
expect(myElement).not.toBeVisible();
```

By testing what the user sees (whether the element is visible, rather than whether it has a certain class), you’re testing *behavior*, you savvy tester, you.

There are also lots of other useful DOM specific assertions, for example: `[toHaveFocus](https://github.com/testing-library/jest-dom#tohavefocus)` and `[toBeChecked](https://github.com/testing-library/jest-dom#tobechecked)` . This makes for robust, concise, and extremely readable test code.

Since the jest-dom assertions do not work with Enzyme wrapper objects, they are not available to use in Enzyme (at least not in any way I could figure out). Another item in the “plus” column for Testing Library.

## ESLint Plugins

To go even further in encouraging best practices, both [testing-library](https://github.com/testing-library/eslint-plugin-testing-library) and [jest-dom](https://github.com/testing-library/eslint-plugin-jest-dom) have ESLint plugins to give feedback when you’ve gone astray.

For example, say you want to test that a checkbox is checked by default. You think to yourself, `[toHaveAttribute](https://github.com/testing-library/jest-dom#tohaveattribute)` is the way to go! So you type out your test:

![jest-dom eslint hint for toHaveAttribute(‘checked’)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/akilw4rgc2nrmwy0s0p5.png)

Wait a minute… what’s that angry red line under `toHaveAttribute`? A mouseover reveals that `[toBeChecked](https://github.com/testing-library/jest-dom#tobechecked)` is preferred here. Nice way to be reminded of best practices (and even possibly learn a new assertion).

## Helpful Hints on Roles

Sometimes it’s hard to know which role to specify when searching for elements. Never fear — if you search for an element by role and Testing Library can’t find it, the test output tries to steer you right. For example:

![Test output shows “link” role instead of “heading” role for $12.99 text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/70gz14qj7x9pn4shry1m.png)

Ooh! So I guess that element has a role of ‘link’ and not a role of ‘heading.’ Thanks, Testing Library. 😁

### Conclusion

I tinkered with Testing Library on a small project, and I can see why it’s gained so much momentum. The opinionated library encourages best practices such as testing behavior over implementation, and writing accessible code. Its jest-dom assertion library provides simple, readable tests. Finally, the ESLint plugins and test output help with best practices and finding elements. I am a big fan!

![photo of large fan](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pw2zfwvvoa32ofg94ozi.jpeg)

<figcaption>Photo by <a href="https://www.pexels.com/@enriquezafra?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels" data-href="https://www.pexels.com/@enriquezafra?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels" class="markup--anchor markup--figure-anchor" rel="noopener" target="_blank"><strong>Enrique Zafra</strong></a> from&nbsp;<a href="https://www.pexels.com/photo/white-desk-fan-on-white-table-3675622/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels" data-href="https://www.pexels.com/photo/white-desk-fan-on-white-table-3675622/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels" class="markup--anchor markup--figure-anchor" rel="noopener" target="_blank"><strong>Pexels</strong></a></figcaption>