Reputation: 381
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 getting TypeError: Cannot read property 'match' of undefined
, so it calls the actual useParams
, 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!
Upvotes: 38
Views: 39598
Reputation: 3383
I have this in my setupTests.js
export const mockHistoryPush = jest.fn();
export const mockHistoryGoBack = jest.fn();
export const mockHistoryReplace = jest.fn();
export const mockLocation = jest.fn();
export let mockUseParams = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockHistoryPush,
replace: mockHistoryReplace,
goBack: mockHistoryGoBack,
}),
useLocation: () => mockLocation,
useParams: mockUseParams,
}));
and when I want to use it and change it per test, I do
mockUseParams.mockReturnValue({id: 42});
in each of the tests.
Upvotes: 0
Reputation: 755
I had the same issue and this is what worked for me:
let mockUseParams;
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: jest.fn(() => mockUseParams),
}));
beforeEach(() => mockUseParams = undefined;)
test('MyComponent uses a param', () => {
mockUseParams = { id: 'testId' };
render(<MyComponent />);
});
Upvotes: 0
Reputation: 1
I had the same issue. I mocked useParams like this before describe
const mockedNavigate = jest.fn();
jest.mock("react-router-dom", () => ({
...(jest.requireActual("react-router-dom") as any),
useNavigate: () => mockedNavigate,
useParams: () => ({
id: 223250
})
}));
Upvotes: 0
Reputation: 2875
You might be missing to add other keys of react-router-dom
as is.
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: jest.fn().mockReturnValue({ id: '123' })
}));
Upvotes: 1
Reputation: 435
I had the same issue. I mocked useParams like this:
jest.mock('react-router-dom', () => {
return {
useParams: () => ({
id: '123'
})
}
})
Upvotes: 0
Reputation: 401
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
Upvotes: 37
Reputation: 325
For me mocking react-router-dom fix the issue:
jest.mock('react-router-dom', () => ({
useParams: jest.fn().mockReturnValue({ nifUuid: 'nif123' }),
useHistory: jest.fn()
}));
Upvotes: 0
Reputation: 91
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();
});
});
Upvotes: 9
Reputation: 1
I had the same issue. Calling the "cleanup" function from the "@testing-library/react" helps me:
import { cleanup } from '@testing-library/react';
afterEach(() => {
cleanup();
});
Upvotes: -1
Reputation: 489
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');
});
});
Upvotes: 4
Reputation: 883
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();
});
});
Upvotes: 9