How to Mock useInsertionEffect in React

This article provides a straightforward guide on how to mock the useInsertionEffect hook in React using testing frameworks like Jest or Vitest. You will learn why mocking this hook is necessary—especially when testing components that utilize CSS-in-JS libraries—and explore practical, step-by-step code examples to implement these mocks in your test suites.

Why Mock useInsertionEffect?

The useInsertionEffect hook is designed for CSS-in-JS library authors to inject styles into the DOM before any layout effects (useLayoutEffect) run. Because it runs synchronously before DOM mutations, it can sometimes cause issues in testing environments like JSDOM, which may not fully support style tag injection or layout calculations. Mocking this hook allows you to bypass style injection during unit tests or assert that the hook was called with the correct styling functions.

The cleanest way to mock useInsertionEffect for individual test files is to use jest.spyOn. This allows you to mock the hook’s behavior and restore it after your tests run.

import React from 'react';
import { render } from '@testing-library/react';
import MyStyledComponent from './MyStyledComponent';

describe('MyStyledComponent', () => {
  let useInsertionEffectSpy;

  beforeEach(() => {
    // Mock useInsertionEffect to execute the callback immediately
    useInsertionEffectSpy = jest.spyOn(React, 'useInsertionEffect')
      .mockImplementation((effect) => effect());
  });

  afterEach(() => {
    // Restore the original implementation
    useInsertionEffectSpy.mockRestore();
  });

  it('renders correctly with mocked style insertion', () => {
    const { container } = render(<MyStyledComponent />);
    expect(container).toBeInTheDocument();
    expect(useInsertionEffectSpy).toHaveBeenCalled();
  });
});

Method 2: Global Module Mocking

If you need to mock useInsertionEffect across your entire test suite, you can mock the react module globally. This is useful if multiple third-party dependencies rely on the hook and cause issues in your JSDOM environment.

Create or update your Jest setup file (e.g., setupTests.js) with the following code:

jest.mock('react', () => {
  const originalReact = jest.requireActual('react');
  return {
    ...originalReact,
    // Mock useInsertionEffect to act like a standard useEffect/useLayoutEffect
    useInsertionEffect: jest.fn((effect) => effect()),
  };
});

Method 3: Mocking in Vitest

If you are using Vitest instead of Jest, the syntax is highly similar. You can use vi.spyOn to mock the hook dynamically:

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import React from 'react';
import { render } from '@testing-library/react';
import MyStyledComponent from './MyStyledComponent';

describe('MyStyledComponent in Vitest', () => {
  let useInsertionEffectSpy;

  beforeEach(() => {
    useInsertionEffectSpy = vi.spyOn(React, 'useInsertionEffect')
      .mockImplementation((effect) => effect());
  });

  afterEach(() => {
    useInsertionEffectSpy.mockRestore();
  });

  it('should render successfully', () => {
    render(<MyStyledComponent />);
    expect(useInsertionEffectSpy).toHaveBeenCalled();
  });
});