简体   繁体   English

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

[英]Mocking react-router-dom useHistory and other hooks with jest

I have a CRA and Typescript (.tsx) application.我有一个 CRA 和 Typescript (.tsx) 应用程序。 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 .我正在尝试为需要useHistoryuseRouteMatch的组件编写测试,但它返回错误: 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();
  });

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.首先,你在错误的地方定义了jest.mock ,它必须是静态的,而不是在每个组件安装之前useHistory - 这解决了你的useHistory错误。 Second, you mocked useRouteMatch in a wrong way, it would've thrown that useRouteMatch is not a function.其次,您以错误的方式嘲笑useRouteMatch ,它会抛出useRouteMatch不是函数。 Third, why do you need that __esModule: true ?第三,你为什么需要__esModule: true

Anyways, here's my working solution (I removed some parts that were not relevant):无论如何,这是我的工作解决方案(我删除了一些不相关的部分):

SidebarTreeNav component: 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;

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM