Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Properly mocking useParams hook in jest

I am trying to mock the useParams hook in jest and try to make it dynamic so I can mock it a few times. However, I can only mock it if I hardcode the value. Here's what I got so far:

const mockedUsedNavigate = jest.fn();

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'), // use actual for all non-hook parts
  useNavigate: () => mockedUsedNavigate,
  useParams: () => ({
    hash: '123',
  }),
}));

This works because I am hardcoding the useParam to return a { hash: '123' } object. However, if I try to mock this, it won't work:

const mockedUsedNavigate = jest.fn();

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'), // use actual for all non-hook parts
  useNavigate: () => mockedUsedNavigate,
  useParams: () => jest.fn().mockReturnValue({ hash: '123' })
}));

If I do that, my component will receive an empty value and the value wont be mocked the way I want:

  const { hash = '' } = useParams<{ hash: string }>();
  console.log('hash: ', hash); ---> ''

So I'm not sure what I'm doing wrong... Can anybody point me to the right direction?

like image 534
Jeff Goes Avatar asked Sep 16 '25 11:09

Jeff Goes


1 Answers

useParams generally returns the route parameters based on the current route. So, it's not a function that can be mocked using jest.fn(). useParams hook returns an object of key/value pairs of the dynamic params from the current URL that were matched by the <Route path>. See here ---> React Router docs

When you use jest.fn().mockReturnValue({ hash: '123' }), it returns a function, not an object. Therefore, calling useParams<{ hash: string }>() will result in an empty object ({}).

To mock useParams with a specific value, you can directly return the object with the desired properties. Modify your code below:

    
const mockedUseNavigate = jest.fn();

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'), // use actual for all non-hook parts
  useNavigate: () => mockedUseNavigate,
  useParams: () => ({ hash: '123' }),
}));

This way, when your component calls useParams<{ hash: string }>(), it will receive the object { hash: '123' }. No need for the additional jest.fn() and mockReturnValue.

To mock the useParams with dynamic values in Jest, you can use one of the following ways:

import { render, screen } from '@testing-library/react';
import { BrowserRouter, MemoryRouter, Route, useParams } from 'react-router-dom';

// Mock the useParams hook
jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'),
  useParams: jest.fn(),
}));

describe('YourComponent', () => {
  test('renders with dynamic useParams', () => {
    // Set the desired dynamic value for testing
    useParams.mockReturnValue({ hash: '123' });

    render(
      <MemoryRouter initialEntries={['/your-route/123']}>
        <YourComponent />
      </MemoryRouter>
    );

    // Your testing logic here

    // Ensure that the component received the dynamic value
    const hashValue = screen.getByText(/hash/i).textContent;
    expect(hashValue).toBe('123');
  });
});

OR

import { render } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
import YourComponent from './YourComponent'; // Import your component

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'),
  useParams: jest.fn(),
}));

describe('YourComponent', () => {
  test('should render with dynamic useParams', () => {
    // Mock the dynamic useParams value
    jest.spyOn(require('react-router-dom'), 'useParams').mockReturnValue({ hash: '123' });

    // Render your component within a Router
    render(
      <Router>
        <YourComponent />
      </Router>
    );
  });
});

Here useParams is declared outside the describe() and its value is change in each unit test using jest.spyOn.

OR

let dynamicHash = '123'; // Set your initial value

const mockedUseNavigate = jest.fn();

jest.mock('react-router-dom', () => ({
  ...jest.requireActual('react-router-dom'),
  useNavigate: () => mockedUseNavigate,
  useParams: () => ({ hash: dynamicHash }),
}));
like image 175
Micah Avatar answered Sep 19 '25 01:09

Micah