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