
Build 10x products in minutes by chatting with AI - beyond just a prototype.
How do you test routing in React?
Is the React Router obsolete?
What is the best testing tool for React?
How to check if React Router is installed?
Testing your React applications ensures they behave as expected and are resilient to changes. When it comes to testing navigation and routing, React Router enables seamless client-side navigation in React applications, ensuring that users can move between different views without full-page reloads.
In this article, we’ll cover key concepts, practical examples, and step-by-step approaches for testing React Router. By the end, you’ll understand how to efficiently test router components, validate route paths, and mock navigation flows using React Testing Library.
React Router is an essential tool for client-side navigation in modern React applications. Whether you’re handling route components or nested routes, it’s critical to ensure every page and navigation interaction behaves as expected.
Verifying that the correct component renders for a given route path.
Mocking navigation using the MemoryRouter component.
Checking router history and validating the history stack.
Testing dynamic routing behavior and navigation using the useNavigate hook.
Before we start writing tests, you need to ensure your React Testing Library setup is complete. Here’s a quick setup guide.
npm install --save-dev @testing-library/react @testing-library/jest-dom react-router-dom
Install the necessary packages for testing with the following command:
• @testing-library/react: For testing React components
• @testing-library/jest-dom: Provides custom matchers for assertions
• react-router-dom: Implements React Router."
Assume a simple React Router app with these routes:
• / - Home Page
• /about - About Page
• /dashboard - Dashboard Page (protected route)
In the following example, we create a simple app with three routes (Home, About, and Dashboard) using React Router
// App.js import React from 'react'; import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'; import Home from './Home'; import About from './About'; import Dashboard from './Dashboard'; const App = () => ( <Router> <nav> <Link to="/">Home</Link> <Link to="/about">About</Link> <Link to="/dashboard">Dashboard</Link> </nav> <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/dashboard" element={<Dashboard />} /> </Routes> </Router> ); export default App;
When writing unit tests for React Router, we simulate navigation using React Testing Library and verify the correct component is rendered.
The memoryRouter component is ideal for tests because it keeps navigation in memory rather than relying on a physical window object.
import { render, screen } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; import App from './App'; test('renders the home page by default', () => { render( <MemoryRouter initialEntries={['/']}> <App /> </MemoryRouter> ); expect(screen.getByText('Welcome to the Home Page')).toBeInTheDocument(); }); test('navigates to the about page', async () => { render( <MemoryRouter initialEntries={['/about']}> <App /> </MemoryRouter> ); expect(screen.getByText('About Us')).toBeInTheDocument(); });
In these tests, we pass the initialEntries prop to MemoryRouter to simulate different route paths.
The useNavigate hook helps programmatic navigation in React Router, which can be tested by mocking the hook.
In this example, we mock the useNavigate hook to test that navigation to a specific route occurs correctly.
Sometimes, you want to ensure that a route component renders based on the current URL path.
In this test, we simulate an unauthenticated user being redirected to the login page when attempting to access a protected route.
When React Testing Library tests interact with APIs, mocking responses is essential to avoid relying on actual network calls.
Here, we mock the axios library to simulate an API response without making a real request.
Use MemoryRouter for isolated tests: This ensures routing logic is kept in memory and doesn’t depend on browser APIs.
Mock the useNavigate hook for testing programmatic navigation.
Test components individually and verify their behavior within specific routes.
Simulate different route paths with initialEntries in MemoryRouter.
Always test edge cases, such as invalid paths and redirects.
Testing React Router with React Testing Library is vital for creating reliable and maintainable React applications. By understanding how to test navigation, mock hooks like useNavigate, and validate router components, you can write comprehensive unit tests. Always focus on testing route components, router history, and path-based rendering to ensure your app's routing works seamlessly.
By mastering these techniques, you’ll be well-equipped to test even the most complex React Router implementations.
import { render, fireEvent } from '@testing-library/react';
import { useNavigate } from 'react-router-dom';
import MyComponent from './MyComponent';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: jest.fn(),
}));
test('navigates to a specific route on button click', () => {
const navigate = jest.fn();
useNavigate.mockReturnValue(navigate);
render(<MyComponent />);
fireEvent.click(screen.getByText('Go to Dashboard'));
expect(navigate).toHaveBeenCalledWith('/dashboard');
});import { render, screen } from '@testing-library/react';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import ProtectedRoute from './ProtectedRoute';
import Dashboard from './Dashboard';
// ProtectedRoute handles redirection if the user is not authenticated.
test('redirects to login if user is not authenticated', () => {
render(
<MemoryRouter initialEntries={['/dashboard']}>
<Routes>
<Route path="/dashboard" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />
<Route path="/login" element={<div>Login Page</div>} />
</Routes>
</MemoryRouter>
);
expect(screen.getByText('Login Page')).toBeInTheDocument();
});import { render, screen, waitFor } from '@testing-library/react';
import axios from 'axios';
import UserProfile from './UserProfile';
jest.mock('axios');
test('displays user data after fetching', async () => {
axios.get.mockResolvedValue({ data: { name: 'John Doe' } });
render(<UserProfile />);
await waitFor(() => expect(screen.getByText('John Doe')).toBeInTheDocument());
});