How to Mock BrowserRouter in React Testing

Testing React components that rely on routing can be challenging because BrowserRouter depends on the browser’s history API, which is not fully available in command-line test environments. This article explains how to easily mock or replace BrowserRouter in your unit tests using MemoryRouter from react-router-dom and how to set up a reusable custom render function for your test suite.

Why You Should Replace BrowserRouter in Tests

When you run tests using React Testing Library and Jest, your code executes in a virtual browser environment called JSDOM. Because BrowserRouter reads and writes directly to the browser’s address bar, using it in tests can cause side effects across your test files and makes it difficult to simulate different URLs.

To solve this, you should replace BrowserRouter with MemoryRouter during testing. MemoryRouter stores its location history internally in memory, which prevents it from interacting with the real window object.

Solution 1: Wrapping Components with MemoryRouter

The quickest way to mock BrowserRouter is to wrap the component you are testing with MemoryRouter directly inside your individual test case.

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

test('renders navigation link and matches route', () => {
  render(
    <MemoryRouter initialEntries={['/dashboard']}>
      <MyNavigationComponent />
    </MemoryRouter>
  );

  expect(screen.getByText(/dashboard/i)).toBeInTheDocument();
});

By using the initialEntries prop on MemoryRouter, you can specify the exact path the simulated browser should start on.

Solution 2: Creating a Custom Render Helper

If you have many components that use routing features, wrapping every test manually leads to repetitive code. Instead, you can create a reusable custom render function that automatically wraps components in a router.

Create a test utility file (e.g., test-utils.js):

import { render } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';

const renderWithRouter = (ui, { route = '/' } = {}) => {
  window.history.pushState({}, 'Test page', route);

  return {
    ...render(ui, { wrapper: MemoryRouter }),
  };
};

export * from '@testing-library/react';
export { renderWithRouter };

Now you can import your custom helper and use it in your tests without manually importing MemoryRouter every time:

import { screen, renderWithRouter } from './test-utils';
import MyNavigationComponent from './MyNavigationComponent';

test('renders on the profile page', () => {
  renderWithRouter(<MyNavigationComponent />, { route: '/profile' });
  expect(screen.getByText(/user profile/i)).toBeInTheDocument();
});

Solution 3: Mocking Hooks Directly (useNavigate, useParams)

If you only need to assert that a navigation action occurred (such as clicking a “Back” button) and do not need to test actual page transitions, you can mock specific react-router-dom hooks using your testing framework’s mocking utilities.

Here is how to mock the useNavigate hook using Jest:

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

const mockNavigate = jest.fn();

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

test('calls navigate when the back button is clicked', () => {
  render(<MyComponent />);
  
  fireEvent.click(screen.getByRole('button', { name: /go back/i }));
  
  expect(mockNavigate).toHaveBeenCalledWith(-1);
});