Testing Material-UI Components with createRenderer: Best Practices and Implementation Guide

Use createRenderer from @mui/material/test-utils to automatically configure the theme, Emotion cache, and portal containers required for reliable unit and integration tests of Material-UI components.

Testing Material-UI components with createRenderer eliminates the repetitive boilerplate of manually wrapping components with ThemeProvider and CacheProvider in every test file. This utility, maintained in the mui/material-ui repository, extends React Testing Library to provide automatic styling engine configuration, theme injection, and portal container management.

What is createRenderer and Why Use It

createRenderer is a test utility that returns a render function mirroring the React Testing Library API while injecting Material-UI-specific context. According to the source code in packages/mui-material/src/test-utils/createRenderer.tsx, it automatically wraps your component with a ThemeProvider (defaulting to createTheme()) and a CacheProvider containing a fresh Emotion cache per test.

This architecture prevents style leakage between tests and ensures components relying on global CSS resets behave identically in test and browser environments. The utility also handles portal containers automatically, eliminating manual DOM manipulation for components like Modal or Popover.

Core Architecture and Key Features

Automatic Theme and Cache Isolation

The renderer configures a dedicated CacheProvider using a fresh Emotion cache for every test invocation. As implemented in packages/mui-material/src/test-utils/createRenderer.tsx, this isolation prevents class name collisions and style pollution across test cases. The default theme is generated via createTheme() from packages/mui-material/src/styles/createTheme.ts, though you can override this with custom theme objects.

Portal Container Management

Material-UI components that render via React portals—such as Modal, Menu, and Popover—require a stable DOM attachment point. The utility automatically appends a <div id="mui-test-root"> to document.body before each test, as defined in the portal container logic within packages/mui-material/src/test-utils/createRenderer.tsx. This ensures predictable portal rendering without manual DOM setup.

Automatic Cleanup

After each test, createRenderer registers React Testing Library's cleanup function and clears the Emotion cache. The cleanup logic in packages/mui-material/src/test-utils/cleanup.ts ensures that styles, portal containers, and rendered components are removed, providing a pristine environment for subsequent tests.

Extensibility for Integration Testing

Advanced users can pass a custom theme object or a wrapper option to add additional context providers such as Redux or React Router. The options parameter in packages/mui-material/src/test-utils/createRenderer.tsx accepts these configurations while maintaining the automatic MUI-specific setup.

Practical Implementation Examples

Testing Basic Components

For standard components like Button, the renderer handles theme injection automatically. Import createRenderer from @mui/material/test-utils and destructure the render method to test user interactions.

import * as React from 'react';
import Button from '@mui/material/Button';
import { createRenderer } from '@mui/material/test-utils';
import { screen, fireEvent } from '@testing-library/react';

const { render } = createRenderer();

test('Button calls onClick when clicked', () => {
  const handleClick = jest.fn();

  render(<Button onClick={handleClick}>Click me</Button>);

  fireEvent.click(screen.getByRole('button', { name: /click me/i }));
  expect(handleClick).toHaveBeenCalledTimes(1);
});

Testing Portal-Based Components

Components like Modal automatically attach to the #mui-test-root container created by createRenderer. You can query portal content using standard RTL selectors without manual DOM manipulation.

import * as React from 'react';
import Modal from '@mui/material/Modal';
import { createRenderer } from '@mui/material/test-utils';
import { screen, fireEvent } from '@testing-library/react';

const { render } = createRenderer();

test('Modal opens and closes', () => {
  const [open, setOpen] = React.useState(true);
  
  render(
    <Modal open={open} onClose={() => setOpen(false)}>
      <div data-testid="modal-content">Hello</div>
    </Modal>
  );

  expect(screen.getByTestId('modal-content')).toBeInTheDocument();

  fireEvent.keyDown(document, { key: 'Escape' });
});

Overriding the Default Theme

Pass a custom theme option to createRenderer to test components with specific theme configurations, such as custom typography or palette settings.

import * as React from 'react';
import { createRenderer } from '@mui/material/test-utils';
import { createTheme } from '@mui/material/styles';
import Typography from '@mui/material/Typography';
import { screen } from '@testing-library/react';

const customTheme = createTheme({ 
  typography: { 
    h1: { fontSize: '3rem' } 
  } 
});

const { render } = createRenderer({ theme: customTheme });

test('Typography uses custom theme values', () => {
  render(
    <Typography variant="h1" data-testid="title">
      Title
    </Typography>
  );

  expect(screen.getByTestId('title')).toHaveStyle('font-size: 3rem');
});

Integrating Additional Providers

Use the wrapper option to add custom context providers such as Redux or React Router while maintaining MUI's automatic theme and cache configuration.

import * as React from 'react';
import { createRenderer } from '@mui/material/test-utils';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import Counter from '../Counter';

const mockStore = configureStore([]);
const store = mockStore({ count: 5 });

const { render } = createRenderer({
  wrapper: ({ children }) => <Provider store={store}>{children}</Provider>,
});

test('Counter displays value from Redux store', () => {
  render(<Counter />);
  expect(screen.getByText(/5/)).toBeInTheDocument();
});

Key Source Files in the Material-UI Repository

Understanding the implementation details in the mui/material-ui repository helps you extend or debug the testing utility.

File Purpose Link
packages/mui-material/src/test-utils/createRenderer.tsx Core utility that builds the RTL render function with MUI‑specific wrappers (theme, cache, portal container). view source
packages/mui-material/src/test-utils/themeProvider.tsx Helper that supplies the default ThemeProvider and optional CssBaseline. view source
packages/mui-material/src/styles/createTheme.ts Function to generate MUI themes; frequently imported in tests to customise styling. view source
packages/mui-material/src/styles/cache.ts Defines the Emotion cache creation used by createRenderer. view source
packages/mui-material/src/test-utils/cleanup.ts Registers RTL’s cleanup and clears the Emotion cache after each test. view source

Summary

  • Use createRenderer from @mui/material/test-utils to eliminate manual ThemeProvider and CacheProvider boilerplate in every test file.
  • Automatic isolation via fresh Emotion caches and dedicated portal containers (#mui-test-root) prevents style leakage and DOM pollution between tests.
  • Extensible architecture supports custom themes via the theme option and additional context providers (Redux, Router) via the wrapper option.
  • Automatic cleanup removes rendered components, portal containers, and cached styles after each test, ensuring a pristine environment.

Frequently Asked Questions

What is the difference between createRenderer and React Testing Library's render?

createRenderer wraps React Testing Library's render function with Material-UI-specific providers. While RTL's native render requires manual setup of ThemeProvider and CacheProvider, createRenderer automatically injects these wrappers along with a fresh Emotion cache and portal container, ensuring consistent styling and DOM isolation for MUI components.

How do I test components that use React portals with createRenderer?

You do not need manual DOM setup. createRenderer automatically creates a <div id="mui-test-root"> container and attaches it to document.body before each test, as implemented in packages/mui-material/src/test-utils/createRenderer.tsx. Portal-based components like Modal and Popover automatically render into this container, which is cleaned up after each test.

Can I use createRenderer with Redux or React Router?

Yes. Pass a custom wrapper option to createRenderer to inject additional context providers. The utility composes your custom wrapper with its internal ThemeProvider and CacheProvider, allowing you to test integrated components while maintaining automatic MUI configuration.

Where is the cleanup logic handled in createRenderer?

The cleanup logic is implemented in packages/mui-material/src/test-utils/cleanup.ts and automatically registered by createRenderer. After each test, it invokes React Testing Library's cleanup function and clears the Emotion cache, ensuring that styles, portal containers, and rendered components do not leak between tests.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →