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();
});