Mocking react-router-dom hooks using jest is not working
Solution 1
This works for me to mock useParams and change values for each unit test within the same file:
import React from "react";
import { render } from "@testing-library/react";
import Router from "react-router-dom";
import Component from "./Component";
jest.mock("react-router-dom", () => ({
...jest.requireActual("react-router-dom"),
useParams: jest.fn(),
}));
const createWrapper = () => {
return render(<Cases />);
};
describe("Component Page", () => {
describe("Rendering", () => {
it("should render cases container", () => {
jest.spyOn(Router, 'useParams').mockReturnValue({ id: '1234' })
const wrapper = createWrapper();
expect(wrapper).toMatchSnapshot();
});
it("should render details container", () => {
jest.spyOn(Router, 'useParams').mockReturnValue({ id: '5678' })
const wrapper = createWrapper();
expect(wrapper).toMatchSnapshot();
});
});
});
Just declare useParams
as jest.fn()
outside describe() and then change its values in each unit test with jest.spyOn
Solution 2
I am not sure why, also couldn't find it in the docs of react-router library, but changing react-router-dom
to react-router
in both tests and implementation worked for me.
So it becomes something like this:
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import React from 'react';
import Header from './header';
import { shallow } from 'enzyme';
Enzyme.configure({ adapter: new Adapter() });
describe('<Header />', () => {
jest.mock('react-router', () => ({
useParams: jest.fn().mockReturnValue({ id: '123' }),
}));
it('renders', () => {
const wrapper = shallow(<Header />);
expect(wrapper).toBeTruthy();
});
});
Solution 3
I've had a similar problem, I solved it like this:
import { Route, Router } from "react-router-dom";
import { createMemoryHistory } from "history";
const renderWithRouter = (component) => {
const history = createMemoryHistory({
initialEntries: ["/part1/idValue1/part2/idValue2/part3"],
});
const Wrapper = ({ children }) => (
<Router history={history}>
<Route path="/part1/:id1/part2/:id2/part3">{children}</Route>
</Router>
);
return {
...render(component, { wrapper: Wrapper }),
history,
};
};
describe("test", () => {
it("test desc", async () => {
const { getByText } = renderWithRouter(<MyComponent/>);
expect(getByText("idValue1")).toBeTruthy();
});
});
Solution 4
I tried this mock but it doesn't work to me. Error: Cannot read property 'match' of undefined. It seems the component is not inside a router so it cannot mock the match with params. It works to me:
import { MemoryRouter, Route } from 'react-router-dom';
const RenderWithRouter = ({ children }) => (
<MemoryRouter initialEntries={['uri/Ineed']}>
<Route path="route/Ineed/:paramId">{children}</Route>
</MemoryRouter>
);
const tf = new TestFramework();
describe('<MyComponent />', () => {
tf.init({ title: 'Some test' }, props =>
shallow(
<RenderWithRouter>
<MyComponent {...props} />
</RenderWithRouter>
)
);
it('Some description', () => {
const wrapper = tf.render().html();
expect(wrapper).toContain('something');
});
});
Maxime Côté
Updated on June 19, 2022Comments
-
Maxime Côté almost 2 years
I'm using Enzyme's shallow method to test a component which uses the
useParams
hook to get an ID from the URL params.I'm trying to mock the
useParams
hook so that it does't call the actual method, but it doesn't work. I'm still gettingTypeError: Cannot read property 'match' of undefined
, so it calls the actualuseParams
, and not my mock.My component:
import React from 'react'; import { useParams } from 'react-router-dom'; export default () => { const { id } = useParams(); return <div>{id}</div>; };
Test:
import Enzyme from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import React from 'react'; import Header from './header'; import { shallow } from 'enzyme'; Enzyme.configure({ adapter: new Adapter() }); describe('<Header />', () => { jest.mock('react-router-dom', () => ({ useParams: jest.fn().mockReturnValue({ id: '123' }), })); it('renders', () => { const wrapper = shallow(<Header />); expect(wrapper).toBeTruthy(); }); });
Thank you!
-
Minkesh Jain over 4 yearsThanks @ivan, If someone knows the logic behind it please post it here.
-
Ivan over 4 yearsWell I think I found it:
react-router-dom
does not define hooks. Hooks are defined inreact-router
package. Therefore if you want to mock react router hooks, you will need to mock that package. See: github.com/ReactTraining/react-router/blob/master/packages/… -
Roger Peixoto over 4 yearsEven when I import those hooks from react-router and mock the react-router package, it still gives em the same error Cannot read property 'match' of undefined
-
Benjamin Charais over 3 yearsIn general providing steps that helped you come to this solution can be very useful to others if you their fix is not exactly the same as yours, that aside, nice clean answer.
-
Vity over 3 yearsI forgot to mention, I'm using react-testing-library but I hope the router part at least is similar
-
Mahdiyeh almost 3 yearsThat was exactly what I needed. Thank you!
-
Carl over 2 yearsThis is the only method that worked for me after migrating to v6 from @reach/router.
-
Dykotomee about 2 yearsIf you're going to call
jest.mock
onreact-router
for the purpose of mockinguseParams
, it's probably a good idea to include everything else before theuseParams
mock by adding...jest.requireActual('react-router')
. This ensures that the rest ofreact-router
doesn't get lost.