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