How to Mock useLocation Hook in React

Testing components that rely on the useLocation hook from react-router-dom can be challenging because they depend on the browser’s current URL. This article provides a straightforward guide on how to mock the useLocation hook using Jest and React Testing Library, covering both global module mocking and dynamic route testing using wrapper components.

Method 1: Mocking react-router-dom Globally with Jest

The most direct way to mock useLocation is to use jest.mock() at the top of your test file. This allows you to define a fake implementation of the hook that returns a mock location object.

import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';

// Mock the entire react-router-dom library
jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'),
  useLocation: () => ({
    pathname: '/dashboard',
    search: '?user=test',
    hash: '',
    state: { from: 'login' }
  }),
}));

test('renders component with mocked location data', () => {
  render(<MyComponent />);
  expect(screen.getByText(/dashboard/i)).toBeInTheDocument();
});

Using jest.requireActual ensures that you only mock useLocation while keeping other features of react-router-dom intact.


Method 2: Mocking Dynamically for Individual Tests

If you need to test different paths or search parameters in different test cases within the same file, you can mock the hook dynamically using jest.spyOn.

import * as router from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
  const useLocationSpy = jest.spyOn(router, 'useLocation');

  beforeEach(() => {
    useLocationSpy.mockClear();
  });

  test('handles dashboard path', () => {
    useLocationSpy.mockReturnValue({
      pathname: '/dashboard',
      search: '',
      hash: '',
      state: null,
    });

    render(<MyComponent />);
    expect(screen.getByText('Welcome to Dashboard')).toBeInTheDocument();
  });

  test('handles settings path', () => {
    useLocationSpy.mockReturnValue({
      pathname: '/settings',
      search: '',
      hash: '',
      state: null,
    });

    render(<MyComponent />);
    expect(screen.getByText('Settings Page')).toBeInTheDocument();
  });
});

Instead of manually mocking useLocation with Jest, the official and recommended approach by the React Router team is to wrap your component in a MemoryRouter. This allows you to set the initial location naturally without stubbing library functions.

import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import MyComponent from './MyComponent';

test('renders correctly on a specific route using MemoryRouter', () => {
  render(
    <MemoryRouter initialEntries={['/profile?id=123']}>
      <MyComponent />
    </MemoryRouter>
  );

  expect(screen.getByText(/User ID: 123/i)).toBeInTheDocument();
});

Using MemoryRouter is generally preferred because it tests your component in a way that closely mirrors how it runs in production, reducing the risk of brittle tests that break during library updates.