Skip to content

Commit 8cef60a

Browse files
m98nickservkentcdodds
authored
Add Migrate from Enzyme page (#568)
* add migrate-from-enzyme.md * add instalation guide * update migrate-from-enzyme.md * fix grammar problem Co-authored-by: Nick McCurdy <nick@nickmccurdy.com> * add update, act and finding element sections * add more example, wrapper.instance and shallow render * format and modify wording and examples Co-authored-by: Nick McCurdy <nick@nickmccurdy.com> Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
1 parent 22a69c1 commit 8cef60a

File tree

3 files changed

+376
-0
lines changed

3 files changed

+376
-0
lines changed

docs/preact-testing-library/learn.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ If you're still hungry for more at this point than checkout:
2323
- The react-testing-library:
2424
- [API](../react-testing-library/api.md)
2525
- [Example](../react-testing-library/example-intro.md)
26+
- [Migrate from Enzyme](../react-testing-library/migrate-from-enzyme.md)
2627
- [Sandbox](https://codesandbox.io/s/github/kentcdodds/react-testing-library-examples)
2728
- [FAQ](../react-testing-library/faq.md)
2829
- This YouTube video by LevelUpTuts called
Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
---
2+
id: migrate
3+
title: Migrate from Enzyme
4+
sidebar_label: Migrate from Enzyme
5+
---
6+
7+
This page does not go into detail, but it's for those who have experience in
8+
working with Enzyme and are trying to understand how to move to React Testing
9+
Library. It also has some helpful information for those who are comparing Enzyme
10+
with React Testing Library.
11+
12+
## What is React Testing Library?
13+
14+
React Testing Library is part of an open-source project named
15+
[Testing Library](https://github.com/testing-library). There are several other
16+
helpful tools and libraries in the Testing Library project which you can use
17+
them to write more useful tests. Beside React Testing Library, here are some
18+
other Testing Library's libraries that can help you along the way:
19+
20+
- **[@testing-library/jest-dom](https://github.com/testing-library/jest-dom)**:
21+
jest-dom provides a set of custom jest matchers that you can use to extend
22+
jest. These will make your tests more declarative, clear to read, and to
23+
maintain.
24+
25+
- **[@testing-library/user-event](https://github.com/testing-library/user-event):**
26+
user-event tries to simulate the real events that would happen in the browser
27+
as the user interacts with it. For example, userEvent.click(checkbox) would
28+
change the state of the checkbox.
29+
30+
## Why should I use the React Testing Library?
31+
32+
Enzyme is a good test library. The library and its contributors did so much for
33+
the community. Many of the React Testing Library maintainers used and
34+
contributed to Enzyme for years before developing and working on React Testing
35+
Library. So we want to say, thank you to the contributors of Enzyme!
36+
37+
The primary purpose of the React Testing Library is to give you confidence by
38+
testing your components in the way the user will use them. Users don't care what
39+
happens behind the scenes. They just see and interact with the output. So,
40+
instead of accessing the components' internal API, or evaluating the `state`,
41+
you'll get more confidence by writing your tests based on the component output.
42+
43+
React Testing Library aims to solve the problem that many developers face when
44+
writing tests with Enzyme which allows (and encourages) developers to test
45+
[implementation details](https://kentcdodds.com/blog/testing-implementation-details).
46+
Tests which do this ultimately prevent you from modifying and refactoring the
47+
component without changing the test. As a result, the tests slowed down your
48+
development speed and productivity, since every small change requires rewriting
49+
some part of your tests, even if the change you made does not affect the
50+
component's output.
51+
52+
Re-writing your tests in React Testing library worthwhile because you're trading
53+
tests that slow you down for tests that give you more confidence and increase
54+
your productivity in the long run.
55+
56+
## How to migrate from Enzyme to React Testing Library?
57+
58+
One of the keys to a successful migrate is to do it incrementally, by running
59+
the two test libraries side by side in the same application and porting Enzyme's
60+
tests to React Testing Library one by one. It makes it possible to migrate even
61+
large and complex applications without disrupting other businesses because the
62+
work can be done collaboratively and spread over some time.
63+
64+
## Install React Testing Library
65+
66+
You can check
67+
[this page](https://testing-library.com/docs/react-testing-library/setup) for
68+
the complete installation and setup guide.
69+
70+
Here is what you should do, first you need to install the React Testing Library:
71+
72+
```
73+
npm install --save-dev @testing-library/react @testing-library/jest-dom
74+
```
75+
76+
## Import React Testing Library to your test
77+
78+
Let's say we're using Jest (you can use other test frameworks as well), then you
79+
just have to import the following modules into your test file:
80+
81+
```jsx
82+
// import React so you can use JSX (React.createElement) in your test
83+
import React from 'react'
84+
85+
/**
86+
* render: lets us render the component (like how React would)
87+
* screen: Your utility for finding elements the same way the user does
88+
**/
89+
import { render, screen } from '@testing-library/react'
90+
```
91+
92+
The test structure is as same as how you would write it in Enzyme
93+
94+
```jsx
95+
test('test title', () => {
96+
// Your tests come here...
97+
})
98+
```
99+
100+
> Note: you can also use `describe` and `it` blocks with React Testing Library.
101+
> React Testing Library doesn't replace Jest, just Enzyme. We recommend `test`
102+
> because it helps with this:
103+
> [Avoid Nesting When You're Testing](https://kentcdodds.com/blog/avoid-nesting-when-youre-testing)
104+
105+
## Basic Enzyme to React Testing Library migration examples
106+
107+
One thing to keep in mind that there's not a one-to-one mapping of Enzyme
108+
features to React Testing Library features. Many Enzyme features result in
109+
inefficient tests. Unfortunately, that means many of the features you're
110+
accustomed to with Enzyme will need to be left behind with Enzyme (no more need
111+
for a `wrapper` variable or `wrapper.update()` calls, etc.).
112+
113+
React Testing Library has helpful queries which lets you access your component's
114+
elements and their properties, and here we'll show typical Enzyme tests with
115+
React Testing Library's alternatives.
116+
117+
Let's say we have a `Welcome` component, which just shows a welcome message, and
118+
we will have a look at both Enzyme and React Testing Library tests to learn how
119+
we can test this component:
120+
121+
**React Component**
122+
123+
The following component gets a `name` from `props` and shows a welcome message
124+
in an `h1` element, it also has a text input which users can change to a
125+
different name, and the template updates accordingly. Check the live version on
126+
[Codesandbox](https://codesandbox.io/s/ecstatic-hellman-fh7in)
127+
128+
```jsx
129+
const Welcome = props => {
130+
const [values, setValues] = useState({
131+
firstName: props.firstName,
132+
lastName: props.lastName,
133+
})
134+
135+
const handleChange = event => {
136+
setValues({ ...values, [event.target.name]: event.target.value })
137+
}
138+
139+
return (
140+
<div>
141+
<h1>
142+
Welcome, {values.firstName} {values.lastName}
143+
</h1>
144+
145+
<form name="userName">
146+
<label>
147+
First Name
148+
<input
149+
value={values.firstName}
150+
name="firstName"
151+
onChange={handleChange}
152+
/>
153+
</label>
154+
155+
<label>
156+
Last Name
157+
<input
158+
value={values.lastName}
159+
name="lastName"
160+
onChange={handleChange}
161+
/>
162+
</label>
163+
</form>
164+
</div>
165+
)
166+
}
167+
168+
export default Welcome
169+
```
170+
171+
### Test 1: Render the component, and check if the `h1` value is correct
172+
173+
**Enzyme test**
174+
175+
```jsx
176+
test('has correct welcome text', () => {
177+
const wrapper = shallow(<Welcome firstName="John" lastName="Doe" />)
178+
expect(wrapper.find('h1').text()).to.equal('Welcome, John Doe')
179+
})
180+
```
181+
182+
**React Testing library**
183+
184+
```jsx
185+
test('has correct welcome text', () => {
186+
render(<Welcome firstName="John" lastName="Doe" />)
187+
expect(screen.getByRole('heading')).toHaveTextContent('Welcome, John Doe')
188+
})
189+
```
190+
191+
As you see, both are pretty similar, Enzyme's `shallow` wrapping doesn't descend
192+
down to sub-components, React Testing Library's `render` is more similar to
193+
`mount`.
194+
195+
In React Testing Library, you don't need to assign the `render` result to a
196+
variable (wrapper, or etc), and you can simply access the rendered output by
197+
calling the `screen`. The other good thing to know is that React Testing Library
198+
automatically cleans up the output for each test, so you don't need to call
199+
`cleanup` on Jest's `afterEach` or `beforeEach` function.
200+
201+
The other thing that you might notice is `getByRole` which has `heading` as its
202+
value. `heading` is the accessible role of the `h1` element. You can learn more
203+
about them on
204+
[queries](https://testing-library.com/docs/dom-testing-library/api-queries#byrole)
205+
documentation page. One of the things people quickly learn to love about Testing
206+
Library is how it encourages you to write more accessible applications (because
207+
if it's not accessible, then it's harder to test).
208+
209+
### Test 2: Input texts must have correct value
210+
211+
In the component above, the input text value will be initialized with the
212+
`props.firstName` and `props.lastName` values, and we need to check whether the
213+
value is correct or not
214+
215+
**Enzyme**
216+
217+
```jsx
218+
test('has correct input value', () => {
219+
const wrapper = shallow(<Welcome firstName="John" lastName="Doe" />)
220+
expect(wrapper.find('input[name="firstName"]').value).to.equal('John')
221+
expect(wrapper.find('input[name="lastName"]').value).to.equal('Doe')
222+
})
223+
```
224+
225+
**React Testing Library**
226+
227+
```jsx
228+
test('has correct input value', () => {
229+
render(<Welcome firstName="John" lastName="Doe" />)
230+
expect(screen.getByRole('form')).toHaveFormValues({
231+
firstName: 'John',
232+
lastName: 'Doe',
233+
})
234+
})
235+
```
236+
237+
Cool! It's pretty simple and handy, and the tests are clear enough that we don't
238+
need to talk so much about them. But something that you might notice is that the
239+
`<form>` had a `role="form"` attribute, but what is it?
240+
241+
`role` is one of the accessibility-related attributes that is recommended to use
242+
to improve your web application for people with disabilities. Some elements have
243+
default `role` values and you don't need to set one for them, but some others
244+
like `<div>` do not have one. You could use different approaches to access the
245+
`<div>` element, but we recommend trying to access elements by their implicit
246+
`role` to make sure your component is accessible by people with disabilities and
247+
those who are using screen readers. This
248+
[section](https://testing-library.com/docs/dom-testing-library/api-queries#byrole)
249+
of the query page might help you to understand better.
250+
251+
> Keep in mind that a `<form>` must have a `name` attribute in order to have an
252+
> implicit `role` of `form` (as required by the specification).
253+
254+
React Testing Library aims to test the component, like how users would, users
255+
see the button, heading, form and other elements by their role, not by their
256+
`id` or `class`, or element tag name. When you use React Testing Library, you
257+
should not try to access the DOM like how you would do by
258+
`document.querySelector` API (which you can incidentally use in your tests, but
259+
it's not recommended for the reasons stated in this paragraph).
260+
261+
We made some handy query APIs which help you to access the component elements
262+
very efficiently, and you can see the
263+
[list of available queries](https://testing-library.com/docs/dom-testing-library/api-queries)
264+
in detail.
265+
266+
Something else that people have a problem with is that they're not sure which
267+
query should they use, luckily we have a great page which explains
268+
[which query to use](https://testing-library.com/docs/guide-which-query), so
269+
don't forget to check it out!
270+
271+
If you still have a problem with the React Testing Library's queries, and you're
272+
not sure which query to use, then check out
273+
[testing-playground.com](https://testing-playground.com) and the accompanying
274+
Chrome extension
275+
**[Testing Playground](https://chrome.google.com/webstore/detail/testing-playground/hejbmebodbijjdhflfknehhcgaklhano/related)**
276+
that aims to enable developers to find a better query when writing tests, and it
277+
helps you find the best queries to select elements. It allows you to inspect the
278+
element hierarchies in the Chrome Developer Tools, and provides you with
279+
suggestions on how to select them, while encouraging good testing practices.
280+
281+
## using act() and wrapper.update()
282+
283+
In Enzyme, for some asynchronous purposes, you have to call `act()` to run your
284+
tests correctly, but in React Testing Library you don't need to use `act()` most
285+
of the time since it wraps APIs with `act()` so you don't need to manually wrap
286+
it.
287+
288+
`update()` syncs the Enzyme component tree snapshot with the react component
289+
tree, often time you might see `wrapper.update()` in Enzyme tests, but React
290+
Testing Library does not need something like that, good for you since you need
291+
to handle fewer things!
292+
293+
## Simulate user events
294+
295+
There are two ways to simulate user events, one is a perfect library named
296+
[`user-event`](https://github.com/testing-library/user-event), and the other way
297+
is to use
298+
[`fireEvent`](https://testing-library.com/docs/dom-testing-library/api-events).
299+
`user-event` is actually built on top of `fireEvent` which simply calls
300+
`dispatchEvent` on the element given. However, `user-event` is generally
301+
recommended because it ensures that all the events are fired in the correct
302+
order for typical user interactions which helps to ensure your tests resemble
303+
the way your software is used.
304+
305+
To use the `@testing-library/user-event` module, you first need to install it:
306+
307+
```
308+
npm install --save-dev @testing-library/user-event @testing-library/dom
309+
```
310+
311+
Now you can import it into your test:
312+
313+
```jsx
314+
import userEvent from '@testing-library/user-event'
315+
```
316+
317+
To demonstrate how to use `user-event` library, imagine we have a component
318+
named Checkbox, and it only shows a checkbox, and we want to simulate the user
319+
event with this component, here is the component:
320+
321+
```jsx
322+
// Checkbox.js
323+
import React from 'react'
324+
const Checkbox = () => {
325+
return (
326+
<div>
327+
<label htmlFor="checkbox">Check</label>
328+
<input id="checkbox" type="checkbox" />
329+
</div>
330+
)
331+
}
332+
333+
export default Checkbox
334+
```
335+
336+
And here we want to test when a user click on the checkbox, does the value
337+
change to “checked”? So, let's see how we write a test for that case:
338+
339+
```jsx
340+
test('handles click correctly', () => {
341+
render(<Checkbox />)
342+
343+
userEvent.click(screen.getByText('Check'))
344+
expect(screen.getByLabelText('Check')).toBeChecked()
345+
})
346+
```
347+
348+
Nice! With the help of other modules provided by the Testing Library, we can
349+
test our components smoothly! To learn more about the `user-event` library, you
350+
can have a look at its
351+
[GitHub repository](https://github.com/testing-library/user-event#table-of-contents)
352+
353+
### Triggering class methods in tests (`wrapper.instance()`)
354+
355+
As we already discussed, we are against testing implementation details and
356+
things that uses are not aware of it, and we aim to test and interact with the
357+
component like how our users would.
358+
359+
> if your test uses instance() or state(), know that you're testing things that
360+
> the user couldn't possibly know about or even care about, which will take your
361+
> tests further from giving you confidence that things will work when your user
362+
> uses them.
363+
> [Kent C. Dodds](https://kentcdodds.com/blog/why-i-never-use-shallow-rendering#calling-methods-in-react-components)
364+
365+
If you're unsure how to test something internal within your component, then take
366+
a step back and consider: "What does the user do to trigger this code to run."
367+
Then make your test do that.
368+
369+
### How to `shallow` render a component?
370+
371+
Generally, you should avoid mocking out components. However, if you need to,
372+
then it's pretty trivial using
373+
[Jest's mocking](https://jestjs.io/docs/en/manual-mocks.html) feature. (see our
374+
[FAQ](https://testing-library.com/docs/react-testing-library/faq))

website/sidebars.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"react-testing-library/example-intro",
2828
"react-testing-library/setup",
2929
"react-testing-library/api",
30+
"react-testing-library/migrate-from-enzyme",
3031
"react-testing-library/faq",
3132
"react-testing-library/cheatsheet"
3233
]

0 commit comments

Comments
 (0)