-
Notifications
You must be signed in to change notification settings - Fork 7
Investigate react testing library as Enzyme replacement
https://github.com/kentcdodds/react-testing-library
The react-testing-library is a very lightweight solution for testing React components. It provides light utility functions on top of react-dom and react-dom/test-utils, in a way that encourages better testing practices. Its primary guiding principle is:
The more your tests resemble the way your software is used, the more confidence they can give you.
Is it worth replacing Enzyme with RTL? What are the pros and cons?
Enzyme | RTL |
---|---|
Uses shallow & deep rendering. Shallow rendering faster than mounting |
Doesn’t use shallow rendering. Case against using shallow rendering by RTL author e.g. |
Behind new React features e.g. getDerivedStateFromError in errorBoundary |
In sync with new features |
Simulate events e.g. wrapper.find('[data-test="btn-add-question-page"]').simulate("click");
|
Click events e.g. fireEvent.click(buttonEl)
|
Instance of React components and snapshot | Works with actual DOM nodes which can be queried |
Find components in render or uses [data-testid] selector e.g. wrapper.find(NavigationSidebar) or wrapper.find('[data-test="side-nav"]')
|
Tries to more closely resemble how a user would use page. e.g. getByLabelText to find form labelor getByText to find element with text.Can also use [date-testid] as fallback alternative |
Things that react-testing-library cannot do (out of the box):
- shallow rendering
- Static rendering (like enzyme's render function).
- Pretty much most of enzyme's methods to query elements (like find) which include the ability to find by a component class or even its displayName (again, the user does not care what your component is called and neither should your test). Note: react-testing-library supports querying for elements in ways that encourage accessibility in your components and more maintainable tests.
- Getting a component instance (like enzyme's instance)
- Getting and setting a component's props (props())
- Getting and setting a component's state (state())
All of these things are things which users of your component cannot do, so your tests shouldn't do them either.
import React from 'react'
import {render, Simulate, wait} from 'react-testing-library'
// this adds custom expect matchers
import 'react-testing-library/extend-expect'
// the mock lives in a __mocks__ directory
import axiosMock from 'axios'
import GreetingFetcher from '../greeting-fetcher'
test('displays greeting when clicking Load Greeting', async () => {
// Arrange
axiosMock.get.mockImplementationOnce(({name}) =>
Promise.resolve({
data: {greeting: `Hello ${name}`},
}),
)
const {getByLabelText, getByText, getByTestId, container} = render(
<GreetingFetcher />,
)
// Act
getByLabelText('name').value = 'Mary'
Simulate.click(getByText('Load Greeting'))
// let's wait for our mocked `get` request promise to resolve
// wait will wait until the callback doesn't throw an error
await wait(() => getByTestId('greeting-text'))
// Assert
expect(axiosMock.get).toHaveBeenCalledTimes(1)
expect(axiosMock.get).toHaveBeenCalledWith(url)
// here's a custom matcher!
expect(getByTestId('greeting-text')).toHaveTextContent('Hello Mary')
// snapshots work great with regular DOM nodes!
expect(container.firstChild).toMatchSnapshot()
})