How to Test React Router in React
Testing routing is essential for ensuring users can navigate your application seamlessly without encountering broken links or missing pages. This article provides a straightforward guide on how to test React Router in a React application using React Testing Library and Jest. You will learn how to set up memory routers, assert that the correct components render based on the URL, and test user-driven navigation.
Why Use MemoryRouter for Testing?
When testing React components that use React Router, rendering them
directly will cause errors because router hooks (like
useNavigate or useParams) and components (like
<Link>) require a router context to function.
Instead of using BrowserRouter, which relies on the
browser’s history API, you should use MemoryRouter from
react-router-dom in your tests. MemoryRouter
stores its location history internally in memory, making it ideal for
isolated unit and integration tests.
Testing Route Rendering
To test if a specific component renders at a given URL, wrap your
component tree in a MemoryRouter and use the
initialEntries prop to define the starting URL path.
Here is an example of testing that the correct page renders for a specific route:
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import App from './App'; // Assumes App contains your Routes definition
test('renders the About page when navigating to /about', () => {
render(
<MemoryRouter initialEntries={['/about']}>
<App />
</MemoryRouter>
);
// Assert that the About page content is visible
const headerElement = screen.getByRole('heading', { name: /about us/i });
expect(headerElement).toBeInTheDocument();
});Testing Navigation Between Pages
To test navigation, you can simulate a user clicking a navigation
link using @testing-library/user-event and assert that the
DOM updates to show the new page.
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { MemoryRouter } from 'react-router-dom';
import App from './App';
test('navigates from home page to contact page on link click', async () => {
render(
<MemoryRouter initialEntries={['/']}>
<App />
</MemoryRouter>
);
// Verify we start on the home page
expect(screen.getByText(/welcome to our website/i)).toBeInTheDocument();
// Find and click the contact link
const contactLink = screen.getByRole('link', { name: /contact/i });
await userEvent.click(contactLink);
// Verify the contact page content is now visible
expect(screen.getByText(/get in touch with us/i)).toBeInTheDocument();
});Testing URL Parameters
If your routes utilize dynamic URL parameters (e.g.,
/users/:id), you can test them by passing the dynamic path
into the initialEntries array.
import { render, screen } from '@testing-library/react';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
import UserProfile from './UserProfile'; // Component using useParams()
test('renders user profile based on URL parameter', () => {
render(
<MemoryRouter initialEntries={['/users/42']}>
<Routes>
<Route path="/users/:id" element={<UserProfile />} />
</Routes>
</MemoryRouter>
);
// Assert that the component successfully extracted '42' from the URL
expect(screen.getByText(/user id: 42/i)).toBeInTheDocument();
});