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.