Migrate from Enzyme
This page does not go into detail, but it's for those who have experience in working with Enzyme and are trying to understand how to move to React Testing Library. It also has some helpful information for those who are comparing Enzyme with React Testing Library.
What is React Testing Library?
React Testing Library is part of an open-source project named Testing Library. There are several other helpful tools and libraries in the Testing Library project which you can use to write more useful tests. Besides React Testing Library, here are some other Testing Library's libraries that can help you along the way:
@testing-library/jest-dom: jest-dom provides a set of custom jest matchers that you can use to extend jest. These will make your tests more declarative, clear to read, and to maintain.
@testing-library/user-event: user-event tries to simulate the real events that would happen in the browser as the user interacts with it. For example, userEvent.click(checkbox) would change the state of the checkbox.
Why should I use the React Testing Library?
Enzyme is a good test library. The library and its contributors did so much for the community. Many of the React Testing Library maintainers used and contributed to Enzyme for years before developing and working on React Testing Library. So we want to say, thank you to the contributors of Enzyme!
The primary purpose of the React Testing Library is to give you confidence by
testing your components in the way the user will use them. Users don't care what
happens behind the scenes. They just see and interact with the output. So,
instead of accessing the components' internal API, or evaluating the state
,
you'll get more confidence by writing your tests based on the component output.
React Testing Library aims to solve the problem that many developers face when writing tests with Enzyme which allows (and encourages) developers to test implementation details. Tests which do this ultimately prevent you from modifying and refactoring the component without changing the test. As a result, the tests slowed down your development speed and productivity, since every small change requires rewriting some part of your tests, even if the change you made does not affect the component's output.
Re-writing your tests in React Testing library is worthwhile, because you're trading tests that slow you down for tests that give you more confidence and increase your productivity in the long run.
How to migrate from Enzyme to React Testing Library?
One of the keys to a successful migration is to do it incrementally, by running the two test libraries side by side in the same application and porting Enzyme's tests to React Testing Library one by one. It makes it possible to migrate even large and complex applications without disrupting other businesses because the work can be done collaboratively and spread over some time.
Install React Testing Library
You can check this page for the complete installation and setup guide.
Here is what you should do, first you need to install the React Testing Library:
Import React Testing Library to your test
Let's say we're using Jest (you can use other test frameworks as well), then you just have to import the following modules into your test file:
The test structure is as same as how you would write it in Enzyme
Note: you can also use
describe
andit
blocks with React Testing Library. React Testing Library doesn't replace Jest, just Enzyme. We recommendtest
because it helps with this: Avoid Nesting When You're Testing
Basic Enzyme to React Testing Library migration examples
One thing to keep in mind that there's not a one-to-one mapping of Enzyme
features to React Testing Library features. Many Enzyme features result in
inefficient tests. Unfortunately, that means many of the features you're
accustomed to with Enzyme will need to be left behind with Enzyme (no more need
for a wrapper
variable or wrapper.update()
calls, etc.).
React Testing Library has helpful queries which lets you access your component's elements and their properties, and here we'll show typical Enzyme tests with React Testing Library's alternatives.
Let's say we have a Welcome
component, which just shows a welcome message, and
we will have a look at both Enzyme and React Testing Library tests to learn how
we can test this component:
React Component
The following component gets a name
from props
and shows a welcome message
in an h1
element, it also has a text input which users can change to a
different name, and the template updates accordingly. Check the live version on
Codesandbox
h1
value is correct
Test 1: Render the component, and check if the Enzyme test
React Testing library
As you see, both are pretty similar, Enzyme's shallow
wrapping doesn't descend
down to sub-components, React Testing Library's render
is more similar to
mount
.
In React Testing Library, you don't need to assign the render
result to a
variable (wrapper, or etc), and you can simply access the rendered output by
calling the screen
. The other good thing to know is that React Testing Library
automatically cleans up the output for each test, so you don't need to call
cleanup
on Jest's afterEach
or beforeEach
function.
The other thing that you might notice is getByRole
which has heading
as its
value. heading
is the accessible role of the h1
element. You can learn more
about them on queries
documentation page. One of the things people quickly learn to love about Testing
Library is how it encourages you to write more accessible applications (because
if it's not accessible, then it's harder to test).
Test 2: Input texts must have correct value
In the component above, the input text value will be initialized with the
props.firstName
and props.lastName
values, and we need to check whether the
value is correct or not
Enzyme
React Testing Library
Cool! It's pretty simple and handy, and the tests are clear enough that we don't
need to talk so much about them. But something that you might notice is that the
<form>
had a role="form"
attribute, but what is it?
role
is one of the accessibility-related attributes that is recommended to use
to improve your web application for people with disabilities. Some elements have
default role
values and you don't need to set one for them, but some others
like <div>
do not have one. You could use different approaches to access the
<div>
element, but we recommend trying to access elements by their implicit
role
to make sure your component is accessible by people with disabilities and
those who are using screen readers. This
section of the query page might
help you to understand better.
Keep in mind that a
<form>
must have aname
attribute in order to have an implicitrole
ofform
(as required by the specification).
React Testing Library aims to test the component, like how users would, users
see the button, heading, form and other elements by their role, not by their
id
or class
, or element tag name. When you use React Testing Library, you
should not try to access the DOM like how you would do by
document.querySelector
API (which you can incidentally use in your tests, but
it's not recommended for the reasons stated in this paragraph).
We made some handy query APIs which help you to access the component elements very efficiently, and you can see the list of available queries in detail.
Something else that people have a problem with is that they're not sure which query should they use, luckily we have a great page which explains which query to use, so don't forget to check it out!
If you still have a problem with the React Testing Library's queries, and you're
not sure which query to use, then check out
testing-playground.com and the accompanying
Chrome extension
Testing Playground
that aims to enable developers to find a better query when writing tests, and it
helps you find the best queries to select elements. It allows you to inspect the
element hierarchies in the Chrome Developer Tools, and provides you with
suggestions on how to select them, while encouraging good testing practices.
using act() and wrapper.update()
In Enzyme, for some asynchronous purposes, you have to call act()
to run your
tests correctly, but in React Testing Library you don't need to use act()
most
of the time since it wraps APIs with act()
so you don't need to manually wrap
it.
update()
syncs the Enzyme component tree snapshot with the react component
tree, often time you might see wrapper.update()
in Enzyme tests, but React
Testing Library does not need something like that, good for you since you need
to handle fewer things!
Simulate user events
There are two ways to simulate user events, one is a perfect library named
user-event
, and the other way
is to use fireEvent
. user-event
is
actually built on top of fireEvent
which simply calls dispatchEvent
on the
element given. However, user-event
is generally recommended because it ensures
that all the events are fired in the correct order for typical user interactions
which helps to ensure your tests resemble the way your software is used.
To use the @testing-library/user-event
module, you first need to install it:
Now you can import it into your test:
To demonstrate how to use user-event
library, imagine we have a component
named Checkbox, and it only shows a checkbox, and we want to simulate the user
event with this component, here is the component:
And here we want to test when a user click on the checkbox, does the value change to “checked”? So, let's see how we write a test for that case:
Nice! With the help of other modules provided by the Testing Library, we can
test our components smoothly! To learn more about the user-event
library, you
can have a look at its
GitHub repository
wrapper.instance()
)
Triggering class methods in tests (As we already discussed, we are against testing implementation details and things that users are not aware of, and we aim to test and interact with the component like how our users would.
if your test uses instance() or state(), know that you're testing things that the user couldn't possibly know about or even care about, which will take your tests further from giving you confidence that things will work when your user uses them. Kent C. Dodds
If you're unsure how to test something internal within your component, then take a step back and consider: "What does the user do to trigger this code to run." Then make your test do that.
shallow
render a component?
How to Generally, you should avoid mocking out components. However, if you need to, then it's pretty trivial using Jest's mocking feature. (see our FAQ)