How to Test HashRouter in React
Testing routing in React applications is crucial for ensuring a
seamless user experience, but testing components that rely on
HashRouter can be tricky due to how it manages the URL
hash. This article provides a straightforward guide on how to test React
components wrapped in a HashRouter using React Testing
Library and Jest. You will learn the industry-standard approach of using
MemoryRouter for unit tests, as well as how to test actual
HashRouter behavior by manipulating the window location
hash directly.
Method 1: Using MemoryRouter (Recommended)
The most reliable and recommended way to test components that use
HashRouter is to substitute it with
MemoryRouter in your test environment. Because
HashRouter relies on the browser’s window history, it can
introduce side effects and state leakage between tests.
MemoryRouter, on the other hand, stores its locations in
memory, making it ideal for isolated unit tests.
Here is how you can test your routed components using
MemoryRouter:
import { render, screen } from '@testing-library/react';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
import AboutPage from './AboutPage';
test('renders the AboutPage component when navigating to /about', () => {
render(
<MemoryRouter initialEntries={['/about']}>
<Routes>
<Route path="/about" element={<AboutPage />} />
</Routes>
</MemoryRouter>
);
// Assert that the element unique to the About Page is in the document
expect(screen.getByText(/about us/i)).toBeInTheDocument();
});By using MemoryRouter and passing the target route to
the initialEntries prop, you can simulate any application
state without touching the actual browser URL.
Method 2: Testing HashRouter Directly
If your test suite strictly requires you to verify the actual
behavior of HashRouter and how it interacts with the window
object, you can test it directly by manually updating the
window.location.hash before rendering the component.
import { render, screen } from '@testing-library/react';
import { HashRouter, Routes, Route } from 'react-router-dom';
import AboutPage from './AboutPage';
describe('HashRouter Integration', () => {
afterEach(() => {
// Clean up the hash after each test to prevent test cross-contamination
window.location.hash = '';
});
test('navigates to the correct route based on window hash', () => {
// Set the hash manually before rendering
window.location.hash = '#/about';
render(
<HashRouter>
<Routes>
<Route path="/about" element={<AboutPage />} />
</Routes>
</HashRouter>
);
expect(screen.getByText(/about us/i)).toBeInTheDocument();
});
});Important Considerations for Direct Testing
- Test Isolation: Always reset
window.location.hashin theafterEachblock. If you do not, the hash from one test will persist into the next, causing false positives or unexpected failures. - JSDOM Limitations: Testing environments like Jest use JSDOM under the hood. While JSDOM supports basic hash manipulation, it may not perfectly replicate complex browser navigation events. For highly complex routing behaviors, end-to-end testing tools like Cypress or Playwright are recommended.