How to Test useParams Hook in React
Testing the useParams hook from React Router is
essential for ensuring your components correctly read and respond to
dynamic URL parameters. This guide provides a straightforward,
step-by-step approach to testing components that utilize
useParams using React Testing Library and Jest. You will
learn the two most common and effective methods: wrapping your component
in a MemoryRouter and mocking the
react-router-dom library directly.
The Component Under Test
To demonstrate how to test useParams, we will use a
simple component called UserProfile that retrieves an
id from the URL and displays it.
import React from 'react';
import { useParams } from 'react-router-dom';
export default function UserProfile() {
const { id } = useParams();
return <h1>User Profile: {id}</h1>;
}Method 1: Using MemoryRouter (Recommended)
The most reliable way to test useParams is to wrap your
component in a MemoryRouter from
react-router-dom. This approach simulates actual routing
behavior in your application without mocking external dependencies,
making your tests more robust and closer to real-world usage.
import React from 'react';
import { render, screen } from '@testing-library/react';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
import UserProfile from './UserProfile';
test('renders user profile with ID from URL parameter', () => {
render(
<MemoryRouter initialEntries={['/users/123']}>
<Routes>
<Route path="/users/:id" element={<UserProfile />} />
</Routes>
</MemoryRouter>
);
// Assert that the component correctly reads "123" from the URL
expect(screen.getByText('User Profile: 123')).toBeInTheDocument();
});How it works:
MemoryRouter: Allows you to specify the browser’s history location in memory using theinitialEntriesprop.RoutesandRoute: Define the path structure/users/:idso React Router knows how to parse the parameter from the URL/users/123.
Method 2: Mocking useParams with Jest
If you prefer to isolate your unit test and avoid rendering routing
wrappers, you can mock the useParams hook directly using
Jest. This method is faster but relies on internal implementation
details of the routing library.
import React from 'react';
import { render, screen } from '@testing-library/react';
import { useParams } from 'react-router-dom';
import UserProfile from './UserProfile';
// Mock the entire react-router-dom library
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: jest.fn(),
}));
test('renders user profile with mocked useParams value', () => {
// Define the mock return value for this specific test
useParams.mockReturnValue({ id: '456' });
render(<UserProfile />);
// Assert that the component correctly renders the mocked ID
expect(screen.getByText('User Profile: 456')).toBeInTheDocument();
});How it works:
jest.mock: Intercepts imports fromreact-router-dom.jest.requireActual: Retains the actual functionality of other React Router exports (likeLinkorNavigate) while allowing you to overrideuseParams.useParams.mockReturnValue: Explicitly defines what the hook should return when the component executes.