How to Mock Render Props in React
Testing React components that use the render props pattern can sometimes be challenging because the UI rendering logic is passed dynamically as a function. This article provides a straightforward guide on how to mock render props in React using Jest and React Testing Library, covering both mocking the component that provides the render prop and passing mock functions directly.
Method 1: Mocking the Provider Component
If you are testing a component that consumes a render prop (for example, a data-fetching component), you can mock the provider component so it immediately executes the render prop with dummy data.
Consider a UserProfile component that uses a
UserDataProvider component:
// UserProfile.js
import { UserDataProvider } from './UserDataProvider';
export function UserProfile() {
return (
<UserDataProvider render={(user) => <h1>Welcome, {user.name}</h1>} />
);
}To mock UserDataProvider so it instantly renders its
render prop with mock data, write your Jest test like this:
import { render, screen } from '@testing-library/react';
import { UserProfile } from './UserProfile';
// Mock the provider component
jest.mock('./UserDataProvider', () => ({
UserDataProvider: ({ render }) => render({ name: 'John Doe' })
}));
test('renders welcome message with mocked user data', () => {
render(<UserProfile />);
expect(screen.getByText('Welcome, John Doe')).toBeInTheDocument();
});In this setup, jest.mock intercepts the import of
UserDataProvider and replaces it with a mock component that
immediately calls the render prop with the dummy payload
{ name: 'John Doe' }.
Method 2: Mocking Render Props as Children
Sometimes, the render prop is passed as the children of
the component rather than a specific render prop. The
mocking strategy remains almost identical.
If your consumer component looks like this:
<UserDataProvider>
{(user) => <h1>Welcome, {user.name}</h1>}
</UserDataProvider>You can mock the provider component by executing the
children prop as a function in your test:
jest.mock('./UserDataProvider', () => ({
UserDataProvider: ({ children }) => children({ name: 'Jane Doe' })
}));Method 3: Spying on the Render Prop Function
If you are testing the provider component itself, your goal is to
ensure that the render prop function is called with the correct
arguments. In this scenario, you do not mock the provider; instead, you
pass a mock function (jest.fn()) as the render prop.
import { render } from '@testing-library/react';
import { UserDataProvider } from './UserDataProvider';
test('calls the render prop with user data', () => {
const renderMock = jest.fn(() => <div />);
render(<UserDataProvider render={renderMock} />);
// Assert that the render prop was called with the expected data
expect(renderMock).toHaveBeenCalledWith(
expect.objectContaining({ name: 'John Doe' })
);
});By using these three patterns, you can effectively isolate your components and test React’s render prop pattern without relying on real backend APIs or complex side effects during your tests.