How to Mock HashRouter in React
Testing React components that rely on HashRouter can be
challenging because of how it interacts with the browser’s window
location hash. This article provides a straightforward guide on how to
mock or substitute HashRouter from
react-router-dom using Jest and React Testing Library,
ensuring your unit tests run reliably in a simulated environment.
Method 1: Substituting with MemoryRouter (Recommended)
The most effective way to “mock” HashRouter in a testing
environment is to substitute it with MemoryRouter. Because
HashRouter relies on browser history and hash changes, it
can cause leaks and unexpected behavior between test runs.
MemoryRouter keeps the history of your URL in memory,
making it ideal for unit tests.
If your component does not hardcode the router itself, you can wrap
your component under test in a MemoryRouter like this:
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import MyComponent from './MyComponent';
test('renders component with routing', () => {
render(
<MemoryRouter initialEntries={['/home']}>
<MyComponent />
</MemoryRouter>
);
expect(screen.getByText(/home/i)).toBeInTheDocument();
});Method 2: Mocking react-router-dom with Jest
If HashRouter is hardcoded inside the component you want
to test and you cannot inject it from the outside, you must mock the
react-router-dom module directly using Jest.
You can mock HashRouter so that it acts as a simple
wrapper that renders its children without any of the routing side
effects:
import { render, screen } from '@testing-library/react';
import App from './App'; // App contains <HashRouter> internally
// Mock react-router-dom
jest.mock('react-router-dom', () => {
const originalModule = jest.requireActual('react-router-dom');
return {
...originalModule,
HashRouter: ({ children }) => <div data-testid="mock-hash-router">{children}</div>,
};
});
test('renders App with mocked HashRouter', () => {
render(<App />);
expect(screen.getByTestId('mock-hash-router')).toBeInTheDocument();
});Method 3: Spying on HashRouter
If you only want to mock the router for specific test suites, you can
use jest.spyOn on the imported module. This keeps your
other tests unaffected if they require the actual router
implementation:
import * as reactRouter from 'react-router-dom';
import { render } from '@testing-library/react';
import App from './App';
test('spies and mocks HashRouter', () => {
const hashRouterSpy = jest.spyOn(reactRouter, 'HashRouter')
.mockImplementation(({ children }) => <div data-testid="spy-router">{children}</div>);
render(<App />);
expect(hashRouterSpy).toHaveBeenCalled();
hashRouterSpy.mockRestore();
});