【问题标题】:useLocation can't be mocked with jest.fn() (while useHistory can be)useLocation 不能用 jest.fn() 来模拟(而 useHistory 可以)
【发布时间】:2021-11-21 07:48:25
【问题描述】:

我正在尝试使用 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 不会抛出任何错误。

有人知道出了什么问题吗?任何建议将不胜感激。


附言

如果我像下面这样在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/>);
});

我不明白为什么会发生这种情况......

【问题讨论】:

  • 我可能遗漏了一部分,但那是什么? :function changeUrl(location.pathname) { ... }?我从未见过像这样的函数声明,这里应该是一个参数,而不是要传递的变量。可以直接在函数内部检索location.pathname,为什么要这样?
  • @RobinMichay 啊,对不起,这不是一个很好的例子。更新了

标签: reactjs jestjs


【解决方案1】:

不要单独模拟每个钩子,而是使用&lt;Memory router&gt;

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

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

【讨论】:

  • 我仍然不知道为什么useLocation 不能被嘲笑……但是这种方法确实可以让我运行测试用例。因此,我将其作为解决方案进行了检查。谢谢!
  • Mocking hooks 直接有一些注意事项。作为一个(合成的)示例:想象您的代码使用useLocation 并且出于任何原因自行解析参数。在某个时刻,您决定将其重构为useParams。如果您直接模拟钩子,则需要更新测试。如果您使用MemoryRouter,您将不需要它 - 直到您也更改逻辑。
猜你喜欢
  • 2021-04-17
  • 2020-08-13
  • 2017-12-19
  • 2020-03-03
  • 1970-01-01
  • 1970-01-01
  • 2021-08-30
  • 2020-05-10
  • 2018-04-16
相关资源
最近更新 更多