How to Mock StaticRouter in React

Testing React components that rely on routing requires setting up a mock routing environment so hooks like useLocation or useNavigate do not throw errors. This article explains how to mock StaticRouter in your unit tests, covering both how to use it as a test wrapper and how to mock the module export itself using Jest and React Testing Library.

Option 1: Using StaticRouter to Mock the Routing Context

If you want to test a component that consumes routing context (like links or route parameters), you can wrap it in StaticRouter within your test. This provides a fixed, non-interactive routing context.

Note that in React Router v6, StaticRouter is imported from react-router-dom/server.

import React from 'react';
import { render, screen } from '@testing-library/react';
import { StaticRouter } from 'react-router-dom/server';
import SidebarNavigation from './SidebarNavigation';

describe('SidebarNavigation Component', () => {
  it('renders navigation links with the correct active state', () => {
    render(
      <StaticRouter location="/dashboard">
        <SidebarNavigation />
      </StaticRouter>
    );

    const dashboardLink = screen.getByRole('link', { name: /dashboard/i });
    expect(dashboardLink).toBeInTheDocument();
  });
});

Using StaticRouter is ideal for testing static server-rendered outputs or when you only need to assert that a component renders correctly at a specific URL.

Option 2: Mocking the StaticRouter Module Export

If the component you are testing imports StaticRouter directly (for example, in a Server-Side Rendering entry point) and you want to mock the component itself to avoid running its actual code during tests, you can use jest.mock.

Here is how to mock the StaticRouter export from react-router-dom/server:

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

// Mock the StaticRouter from react-router-dom/server
jest.mock('react-router-dom/server', () => ({
  StaticRouter: ({ children, location }) => (
    <div data-testid="mock-static-router" data-location={location}>
      {children}
    </div>
  ),
}));

describe('AppServerEntry Component', () => {
  it('wraps the application in the mocked StaticRouter', () => {
    render(<AppServerEntry url="/profile" />);

    const mockRouter = screen.getByTestId('mock-static-router');
    expect(mockRouter).toBeInTheDocument();
    expect(mockRouter).toHaveAttribute('data-location', '/profile');
  });
});

Option 3: Replacing StaticRouter with MemoryRouter in Tests

For most client-side interaction and navigation tests, using MemoryRouter from react-router-dom is preferred over StaticRouter. MemoryRouter keeps the history of your routing in memory, allowing you to test dynamic redirects and navigation actions.

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

test('renders profile page using MemoryRouter', () => {
  render(
    <MemoryRouter initialEntries={['/user/123']}>
      <ProfileCard />
    </MemoryRouter>
  );

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