How to Mock useNavigate in React Router
This article provides a straightforward guide on how to mock the
useNavigate hook from react-router-dom when
writing unit tests with Jest and React Testing Library. You will learn
how to set up a Jest mock, spy on navigation calls, and assert that your
component correctly redirects users.
When writing unit tests for React components that handle navigation,
you need to mock the useNavigate hook. Since unit tests run
in a virtual DOM environment (like JSDOM), standard routing mechanisms
are not fully active, and we must intercept the navigation call to
verify it was triggered with the correct arguments.
Step 1: Mock the
react-router-dom Module
To mock useNavigate, you need to mock the entire
react-router-dom package using jest.mock().
You must preserve the other exports of the library (such as
<Link> or <Route>) while
overriding useNavigate to return a dummy function that Jest
can track.
Here is the setup code you should place at the top of your test file:
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MyComponent from './MyComponent';
// Create a mock function to track the navigation
const mockNavigate = jest.fn();
// Mock the react-router-dom module
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => mockNavigate,
}));Step 2: Write the Test Case
Now that the hook is mocked, you can render your component, simulate user interaction, and assert that the mock navigation function was called with the correct route.
Suppose you have a component with a button that redirects the user to
the /dashboard route:
test('navigates to /dashboard when the button is clicked', async () => {
render(<MyComponent />);
const button = screen.getByRole('button', { name: /go to dashboard/i });
await userEvent.click(button);
// Assert that useNavigate was called with the correct path
expect(mockNavigate).toHaveBeenCalledWith('/dashboard');
});Step 3: Reset the Mock Between Tests
If you have multiple tests in the same file, mock calls can bleed into one another. To prevent false positives, reset the mock function before or after each test run:
beforeEach(() => {
mockNavigate.mockClear();
});