How to Mock Router Routes in React

Testing components that rely on React Router requires simulating the routing environment without running a full browser instance. This article provides a straightforward guide on how to mock router routes in React using React Router’s built-in MemoryRouter for integration tests, as well as how to mock specific routing hooks like useNavigate and useParams using Jest.

The most effective way to mock routes in React Router (v6+) is by wrapping your component in a MemoryRouter. This component stores its locations internally in an array, making it ideal for testing environments like Jest and React Testing Library.

You can define the current path using the initialEntries prop.

import { render, screen } from '@testing-library/react';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
import UserProfile from './UserProfile';

test('renders UserProfile with correct ID from URL', () => {
  render(
    <MemoryRouter initialEntries={['/users/42']}>
      <Routes>
        <Route path="/users/:id" element={<UserProfile />} />
      </Routes>
    </MemoryRouter>
  );

  expect(screen.getByText(/User ID: 42/i)).toBeInTheDocument();
});

Method 2: Mocking React Router Hooks

Sometimes you want to assert that a navigation action has occurred (e.g., clicking a button redirects the user). In this case, you should mock the hooks directly.

Mocking useNavigate

To verify if useNavigate is called with the correct path, mock the react-router-dom library using Jest.

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

const mockNavigate = jest.fn();

// Mock the react-router-dom module
jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'),
  useNavigate: () => mockNavigate,
}));

test('redirects to dashboard on form submission', () => {
  render(<MyForm />);
  
  const submitButton = screen.getByRole('button', { name: /submit/i });
  fireEvent.click(submitButton);

  expect(mockNavigate).toHaveBeenCalledWith('/dashboard');
});

Mocking useParams

If you are writing a unit test for a component and do not want to set up a MemoryRouter wrapper, you can mock useParams directly.

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

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'),
  useParams: () => ({ productId: 'abc-987' }),
}));

test('displays the correct product ID', () => {
  render(<ProductDetail />);
  expect(screen.getByText(/Product: abc-987/i)).toBeInTheDocument();
});