How to Mock useId Hook in React

Testing React components that use the useId hook can sometimes lead to inconsistent snapshot tests or unpredictable ID generation across different test suites. This article provides a straightforward guide on how to mock the useId hook in React using popular testing frameworks like Jest and Vitest, ensuring your tests remain deterministic and stable.

Why Mock useId?

The useId hook in React generates unique, auto-incrementing strings (such as :r0:, :r1:) for accessibility attributes. Because these IDs depend on the component render order and the overall component tree structure, any change to your test setup can alter the generated ID. This frequently breaks snapshot tests and makes element selection unreliable. Mocking useId to return a static, predictable string solves this issue.

Mocking useId in Jest

To mock the useId hook in Jest, you can intercept the react module import and replace the useId implementation with a mock function that returns a static string.

Add the following mock block at the top of your test file, before any component imports:

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

// Mock the useId hook to return a static string
jest.mock('react', () => ({
  ...jest.requireActual('react'),
  useId: () => 'mocked-id',
}));

test('renders with a mocked ID', () => {
  render(<MyComponent />);
  
  const input = screen.getByRole('textbox');
  expect(input.id).toBe('mocked-id');
});

Using jest.requireActual('react') ensures that all other React hooks and features (like useState or useEffect) continue to function normally.

Mocking useId in Vitest

If you are using Vitest instead of Jest, the mocking syntax is highly similar, but utilizes Vitest’s asynchronous module mocking system.

import { render, screen } from '@testing-library/react';
import { vi, test, expect } from 'vitest';
import MyComponent from './MyComponent';

// Mock the useId hook in Vitest
vi.mock('react', async () => {
  const actual = await vi.importActual('react');
  return {
    ...actual,
    useId: () => 'mocked-id',
  };
});

test('renders with a mocked ID in Vitest', () => {
  render(<MyComponent />);
  
  const input = screen.getByRole('textbox');
  expect(input.id).toBe('mocked-id');
});

Mocking with Sequential IDs (Optional)

If your test suite renders multiple components that require unique but predictable IDs, you can modify the mock to use a counter that increments with each call:

let idCounter = 0;

jest.mock('react', () => ({
  ...jest.requireActual('react'),
  useId: () => `mocked-id-${idCounter++}`,
}));

// Remember to reset the counter before each test
beforeEach(() => {
  idCounter = 0;
});

By applying these patterns, your React component tests will output consistent IDs, preventing false negatives in your test pipeline and keeping snapshot tests reliable.