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?
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 }),
}));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With