Published at: September 18, 2021
When it comes to testing React components, there’s been an ongoing debate between React Testing Library and Enzyme. Both have their strengths, but as the React ecosystem continues to evolve, React Testing Library has emerged as the preferred choice for most developers. In this post, we’ll take a deep dive into why React Testing Library has become the standard for testing React components and how you can write better, more effective tests using it.
1. Why React Testing Library Became the Standard
Enzyme was the go-to testing library for React developers for years, providing powerful utilities to mount components, simulate events, and access component instances. However, as React’s API evolved, it became clear that Enzyme wasn’t always keeping up with the changes, especially as new patterns like Hooks emerged. This led to a shift towards React Testing Library.
Key Reasons for the Shift:
- Better Alignment with User Behavior: React Testing Library encourages testing components from the user’s perspective rather than the implementation details. This approach leads to more reliable and maintainable tests.
- Simplified API: React Testing Library provides a simple, intuitive API that focuses on querying elements and simulating user interactions, without needing to access or interact with internal component state.
- Less Reliance on Implementation Details: While Enzyme encouraged tests that often depended on component internals (like accessing props or state), React Testing Library promotes writing tests that focus on how a component behaves as a whole, improving test reliability.
- Built-in Focus on Accessibility: React Testing Library emphasizes accessibility by promoting queries like
getByRole
andgetByLabelText
, making it easier to write tests that ensure your app is accessible to all users.
2. Writing Better Tests with React Testing Library
React Testing Library’s focus is on behavioral testing. Instead of testing the internal details of a component (e.g., its state or props), the tests focus on ensuring that the component interacts correctly with the DOM and behaves as expected when the user interacts with it.
Installing React Testing Library
To get started with React Testing Library, first install it in your project:
npm install --save @testing-library/react @testing-library/jest-dom
You also need to install the jest-dom library, which adds custom matchers for testing DOM elements, such as toBeInTheDocument()
or toHaveTextContent()
.
Example: Testing a Simple Button Click
Let’s say you have a simple component that displays a button. When the button is clicked, it increments a count and displays the new value.
// Counter.js
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment</button>
<span>{count}</span>
</div>
);
};
export default Counter;
You can write a test for this component using React Testing Library like so:
// Counter.test.js
import { render, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import Counter from './Counter';
test('increments counter on button click', () => {
const { getByText } = render(<Counter />);
// Get the button and click it
const button = getByText('Increment');
fireEvent.click(button);
// Assert that the counter increments
const counter = getByText('1');
expect(counter).toBeInTheDocument();
});
In this test:
render
: Renders the component into a virtual DOM for testing.getByText
: Queries the DOM for elements based on their text content.fireEvent.click
: Simulates a click event on the button.expect(...).toBeInTheDocument()
: Asserts that the counter’s new value is present in the DOM.
This test checks the behavior of the component rather than its internal state or props, making it more robust and focused on how the user interacts with the UI.
3. Enzyme vs. React Testing Library: Key Differences
To better understand why React Testing Library has become the standard, let’s compare it with Enzyme across some key aspects:
1. Testing Philosophy
- Enzyme: Encourages testing implementation details (e.g., checking internal state, props, or component methods). This can lead to brittle tests that break when the implementation changes but the behavior remains the same.
- React Testing Library: Encourages testing the component’s behavior, i.e., what the user sees and interacts with. This leads to more robust and maintainable tests because they focus on what matters from a user’s perspective.
2. API Complexity
- Enzyme: Provides a rich API with methods like
mount
,shallow
,find
, andsetState
that allow you to interact with the internal component structure. - React Testing Library: Offers a simpler API that focuses on DOM queries, like
getByText
,getByRole
, andgetByLabelText
, to simulate user interactions.
3. Support for Hooks
- Enzyme: Enzyme’s support for React Hooks was problematic, as it required additional adapters to work with Hooks properly.
- React Testing Library: Fully supports React Hooks out of the box, encouraging developers to write tests that reflect real-world usage, such as simulating user interactions.
4. When to Use Enzyme vs. React Testing Library
While React Testing Library has emerged as the preferred choice for most developers, there are still some cases where Enzyme might be suitable, particularly if you need to:
- Test class components (though class components are being phased out).
- Perform more fine-grained testing of component internals (e.g., state or lifecycle methods).
- Use older codebases that have already integrated Enzyme.
However, for most modern React apps, especially with the increased use of functional components and Hooks, React Testing Library is the better choice for writing maintainable, user-centric tests.
5. Best Practices for Writing Tests with React Testing Library
Here are some best practices to follow when writing tests with React Testing Library:
- Test behavior, not implementation: Focus on what the component does rather than its internal state.
- Query by user-facing properties: Use queries like
getByText
,getByRole
, orgetByLabelText
, which represent how the user interacts with the app. - Avoid unnecessary mocks: Mock only external dependencies when necessary, such as API calls or third-party libraries. Prefer testing components with real data.
- Write simple and clear tests: Keep tests readable and simple. They should express what your component is doing, not how it’s doing it.
Conclusion
The React Testing Library has gained significant traction as the go-to testing solution for React developers. By focusing on user-centric behavior and promoting simplicity, React Testing Library helps developers write tests that are easier to maintain and more aligned with real-world use cases.
While Enzyme still has its place in certain scenarios, React Testing Library has quickly become the standard for testing modern React applications.
So, if you’re starting a new project or modernizing your testing setup, it’s time to make the switch to React Testing Library and begin writing tests that focus on how your app behaves from the user’s perspective.