ReactReact Testing Library

Testing React Render Props Like a Pro with React Testing Library.

By Joel Maria
Picture of the author
Published on
image alt attribute

Ever struggled to test a React component that uses render props? If you’ve worked with this powerful pattern, you know it’s great for sharing logic but can feel tricky to test. Inspired by Kent C. Dodds’ practical approach, this post will show you how to test render props components confidently using React Testing Library. Whether you’re a beginner or a seasoned dev, you’ll learn how to write tests that mimic user behavior and keep your codebase robust. Let’s dive in!

What Are Render Props?

Render props let a component pass a function as a prop to control what gets rendered. Think of it as a way to share behavior while keeping flexibility. For example:

<DataFetcher render={({ data }) => <div>{data}</div>} />

Here, DataFetcher might fetch data and pass it to the render function. Testing this means ensuring the component calls the render prop with the right data and renders correctly.

Why Testing Render Props Matters

Render props are dynamic, so you need to verify that:The render prop function is called with the correct arguments. The component renders the expected UI based on those arguments. Async behavior (like data fetching) works as expected.

Testing with React Testing Library

Let’s test a simple DataFetcher component that uses a render prop to display fetched data. Here’s the component:

import { useState, useEffect } from 'react';

const DataFetcher = ({ render }) => {
  const [data, setData] = useState(null);

  useEffect(() => {
    // Simulate fetching data
    setTimeout(() => setData('Hello, World!'), 1000);
  }, []);

  return render({ data });
};

export default DataFetcher;

Now, let’s write a test using React Testing Library to ensure it works:

import { render, screen, waitFor } from '@testing-library/react';
import DataFetcher from './DataFetcher';

test('DataFetcher calls render prop with fetched data', async () => {
  const mockRender = jest.fn(({ data }) => <div>{data || 'Loading...'}</div>);
  render(<DataFetcher render={mockRender} />);

  // Check initial render
  expect(screen.getByText('Loading...')).toBeInTheDocument();
  expect(mockRender).toHaveBeenCalledWith({ data: null });

  // Wait for data to load
  await waitFor(() => {
    expect(screen.getByText('Hello, World!')).toBeInTheDocument();
  });
  expect(mockRender).toHaveBeenCalledWith({ data: 'Hello, World!' });
});

What’s Happening Here?

  • We create a mock render function to track calls and render content.
  • We use screen.getByText to verify the UI shows “Loading...” initially.
  • waitFor handles the async data fetch, ensuring “Hello, World!” appears.
  • We confirm the render prop was called with the correct data (null initially, then the fetched value).

Best Practices

  1. Test Like a User: Focus on what the user sees (the rendered output), not internal state. React Testing Library encourages this by querying the DOM like a user would.
  2. Avoid Over-Mocking: Don’t mock the render prop excessively—test it as it’s used in the app.
  3. Handle Async Properly: Use waitFor for async operations like data fetching to avoid flaky tests.
  4. Keep Tests Maintainable: Write tests that won’t break if you refactor the component’s internals.

Conclusion

Testing render props doesn’t have to be intimidating. By using React Testing Library and focusing on user-centric tests, you can ensure your components work as expected without digging into implementation details. Try writing a test for your own render props component, and let me know how it goes in the comments!

Resources: