Reputation: 99
I have a CRA and Typescript (.tsx) application. I'm trying to write a test for a component that needs useHistory
and useRouteMatch
but it return the error: TypeError: Cannot read property 'history' of undefined
.
The component:
const SidebarTreeNav: React.FC<Props> = ( { tree, expanded } ) => {
const history = useHistory();
let { url } = useRouteMatch();
const handleClick = useCallback(
( path: string ) => history.push(`${ url }/${ path }`),
[ history ]);
return (
<SidebarTreeNavView expanded={ expanded ?? [ '0' ] }>
<SidebarTreeNavBlock handleClick={ handleClick } tree={ tree } node={ 0 } />
</SidebarTreeNavView>
);
};
export default SidebarTreeNav;
The Test:
beforeEach(() => {
jest.mock('react-router-dom', () => {
const originalModule = jest.requireActual('react-router-dom');
return {
__esModule: true,
...originalModule,
useRouteMatch: { url: '/entry' },
useHistory: jest.fn(),
};
});
shallow = createShallow();
wrapper = shallow(<SidebarTreeNav tree={ [] } />);
});
it('<SidebarTreeNav /> should be defined', () => {
expect(wrapper).toBeDefined();
});
Upvotes: 5
Views: 6037
Reputation: 110
Probably this answer is not needed for you anymore, but I'll post it for future reference.
First, you defined jest.mock
in the wrong place, it has to be static, not mocked before every component mount - that solves your useHistory
error.
Second, you mocked useRouteMatch
in a wrong way, it would've thrown that useRouteMatch
is not a function.
Third, why do you need that __esModule: true
?
Anyways, here's my working solution (I removed some parts that were not relevant):
SidebarTreeNav component:
import React, { useCallback } from 'react';
import { useHistory, useRouteMatch } from 'react-router-dom';
const SidebarTreeNav = () => {
const history = useHistory();
const { url } = useRouteMatch();
const handleClick = useCallback(
(path: string) => history.push(`${url}/${path}`),
[history]
);
// eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
return <div onClick={() => handleClick(url)}>expanded</div>;
};
export default SidebarTreeNav;
test file:
import { shallow, ShallowWrapper } from 'enzyme';
import React from 'react';
import SidebarTreeNav from './SideBarTreeNav';
jest.mock('react-router-dom', () => {
const originalModule = jest.requireActual('react-router-dom');
return {
...originalModule,
useHistory: jest.fn(),
useRouteMatch: jest.fn(() => {
return { url: '/entry' };
}),
};
});
describe('whatever', () => {
let wrapper: ShallowWrapper;
beforeEach(() => {
wrapper = shallow(<Temporary />);
});
it('<SidebarTreeNav /> should be defined', () => {
expect(wrapper).toBeDefined();
});
});
A side note: it's really hard to work with your example because you posted just some part of your code, next time please add a fully replicated js fiddle.
Upvotes: 5