How to Mock useParams Hook in React
Testing React components that rely on dynamic URL parameters requires
mocking the useParams hook from
react-router-dom. This article provides a straightforward
guide on how to mock this hook using Jest and React Testing Library,
covering both static module mocking and dynamic parameter changes for
individual test cases.
Method 1: Mocking useParams globally with Jest
The most direct way to mock useParams is by using
jest.mock(). This approach intercepts the
react-router-dom module and returns a custom value for the
hook while preserving the rest of the library’s functionality.
Add the following block at the top of your test file:
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';
// Mock the react-router-dom library
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: () => ({ id: '123' }),
}));
test('renders component with mock parameter', () => {
render(<MyComponent />);
expect(screen.getByText(/User ID: 123/i)).toBeInTheDocument();
});Using jest.requireActual ensures that other essential
router components, like Link or Navigate,
still function normally during the test run.
Method 2: Dynamic mocking for different test cases
If you need to test how your component behaves with different URL
parameters across multiple tests, you can assign a
jest.fn() to a variable and change its implementation
dynamically.
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';
const mockUseParams = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: () => mockUseParams(),
}));
describe('MyComponent with dynamic params', () => {
beforeEach(() => {
mockUseParams.mockReset();
});
test('handles user ID 123', () => {
mockUseParams.mockReturnValue({ id: '123' });
render(<MyComponent />);
expect(screen.getByText(/User ID: 123/i)).toBeInTheDocument();
});
test('handles user ID 999', () => {
mockUseParams.mockReturnValue({ id: '999' });
render(<MyComponent />);
expect(screen.getByText(/User ID: 999/i)).toBeInTheDocument();
});
});Method 3: The recommended alternative (using MemoryRouter)
While explicitly mocking the hook works well, the recommended
practice in React Testing Library is to avoid mocking library internals.
Instead, wrap your component in a MemoryRouter and define a
route with the parameter you want to test.
import { render, screen } from '@testing-library/react';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
import MyComponent from './MyComponent';
test('renders correct ID using MemoryRouter', () => {
render(
<MemoryRouter initialEntries={['/user/456']}>
<Routes>
<Route path="/user/:id" element={<MyComponent />} />
</Routes>
</MemoryRouter>
);
expect(screen.getByText(/User ID: 456/i)).toBeInTheDocument();
});This integration-style approach is less prone to breaking when you
update react-router-dom and closely mirrors how your
application runs in a real browser environment.