How to Test React Higher-Order Components
Testing Higher-Order Components (HOCs) in React is essential for ensuring that reusable component logic behaves correctly across your application. This article covers the primary strategies for testing HOCs, including testing the enhanced component as a whole and isolating the HOC logic using dummy components. You will learn practical implementation steps using Jest and React Testing Library to write reliable, maintainable tests without exposing internal implementation details.
The Recommended Strategy: Test with a Dummy Component
Because an HOC is a function that accepts a component and returns a new one, the most effective way to test it is by wrapping a simple “dummy” or “mock” component. This allows you to verify that the HOC correctly injects props, alters behavior, or conditionally renders the wrapped component.
Using React Testing Library (RTL), you should focus on testing the observable behavior from the user’s perspective rather than the internal state of the HOC.
Step-by-Step Implementation
Here is how to set up and write a test for an HOC that injects user
authentication data, commonly named withUser.
1. The HOC Code
import React from 'react';
export const withUser = (WrappedComponent) => {
return function WithUserComponent(props) {
const mockUser = { name: 'John Doe', isLoggedIn: true };
return <WrappedComponent {...props} user={mockUser} />;
};
};2. The Test Suite
To test this HOC, create a dummy component inside your test file, wrap it with the HOC, and assert that the injected props are rendered correctly.
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import { withUser } from './withUser';
// 1. Create a simple dummy component
const DummyComponent = ({ user, extraProp }) => (
<div>
<p data-testid="username">{user.name}</p>
<p data-testid="extra">{extraProp}</p>
</div>
);
// 2. Wrap the dummy component with the HOC
const EnhancedComponent = withUser(DummyComponent);
describe('withUser HOC', () => {
test('injects the user prop into the wrapped component', () => {
// Render the enhanced component
render(<EnhancedComponent extraProp="test-value" />);
// Assert that the injected user prop is rendered
expect(screen.getByTestId('username')).toHaveTextContent('John Doe');
});
test('passes down unrelated props to the wrapped component', () => {
render(<EnhancedComponent extraProp="test-value" />);
// Assert that original props are still passed through
expect(screen.getByTestId('extra')).toHaveTextContent('test-value');
});
});Key Aspects to Verify When Testing HOCs
To ensure your HOC is robust, always write test cases for the following behaviors:
- Prop Pass-Through: Ensure that any props passed to the enhanced component are successfully forwarded to the wrapped component. HOCs should not accidentally block or filter out unrelated props.
- Conditional Rendering: If your HOC conditionally
renders the wrapped component (for example, a
withAuthHOC that redirects guests), test both scenarios: when the condition is met (rendering the component) and when it is not (rendering a loader, redirecting, or returning null). - Edge Cases and State Changes: If your HOC manages internal state (like fetching data or tracking scroll positions), trigger those state changes in your test and verify that the wrapped component updates accordingly with the new props.