开玩笑地嘲笑 react-router-dom useHistory 和其他钩子

Moi*_*lzo 4 testing mocking reactjs jestjs react-router-dom

我有一个 CRA 和 Typescript (.tsx) 应用程序。我正在尝试为需要的组件编写测试useHistoryuseRouteMatch但它返回错误:TypeError: Cannot read property 'history' of undefined.

组件:

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;
Run Code Online (Sandbox Code Playgroud)

考试:

  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();
  });

Run Code Online (Sandbox Code Playgroud)

小智 5

您可能不再需要此答案,但我会将其发布以供将来参考。

首先,您jest.mock在错误的位置定义了它,它必须是静态的,而不是在每个组件安装之前进行模拟 - 这可以解决您的useHistory错误。其次,你useRouteMatch以错误的方式嘲笑,它会抛出useRouteMatch不是一个函数。第三,你为什么需要那个__esModule: true

无论如何,这是我的工作解决方案(我删除了一些不相关的部分):

SidebarTreeNav 组件:

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;
Run Code Online (Sandbox Code Playgroud)

测试文件:

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();
  });
});

Run Code Online (Sandbox Code Playgroud)

旁注:使用您的示例真的很难,因为您只发布了部分代码,下次请添加完全复制的 js 小提琴。