useLocation 不能被 jest.fn() 模拟(而 useHistory 可以)

useLocation can't be mocked with jest.fn() (while useHistory can be)

我正在尝试使用 useHistoryuseLocation 为 React 组件编写测试,如下所示:

import { useHistory, useLocation } from 'react-router-dom';

export function MyComponent() {
  let location = useLocation();
  let history = useHistory();

  function changeUrl(param) {
    // some logic here
    if(foo) {
        history.push(location.pathname);
    } else {
        history.push(param)
    } 
  } 

  return (<div>{/* actual elements here */}</div>)
}

这是测试文件:

import { render } from "@testing-library/react";

jest.mock('react-router-dom', () => ({
    ...jest.requireActual('react-router-dom'),
    useLocation: jest.fn().mockImplementation(() => ({ pathname: 'a' })),
    useHistory: jest.fn().mockImplementation(() => ({ push: () => { } })),
}));

it('should do xxx', () => {
    render(<MyComponent/>);
});

这导致

Error: Uncaught [TypeError: Cannot read property 'pathname' of undefined]

错误源自location.pathname。同时,useHistory 不会抛出任何错误。

有人看到哪里出了问题吗?任何建议将不胜感激。


PS

如果我像下面这样在 it 中使用 mockImplementation,则不会发生错误。

jest.mock('react-router-dom', () => ({
    ...jest.requireActual('react-router-dom'),
    useHistory: jest.fn().mockImplementation(() => ({ push: () => { } })),
}));

const { useLocation } = require('react-router-dom');

it('should do xxx', () => {
    useLocation.mockImplementation(() => { pathname: 'a' });

    render(<MyComponent/>);
});

我不明白为什么会这样...

不要单独模拟每个钩子,而是使用 <Memory router>

render(
  <MemoryRouter initial entries={['/a']}>
    <My component/>
  </MemoryRouter>
)

React Router 文档中的更多示例,第 Testing 部分。模拟单个钩子不太灵活。