如何使用 Jest 使用新的 React Router Hooks 模拟 history.push

新手上路,请多包涵

我正在尝试模拟 history.push 在新的 useHistory 挂钩 react-router 并使用 @testing-library/react 。我只是像这里的第一个答案一样嘲笑模块: 如何使用新的反应路由器钩子测试组件?

所以我在做:

 //NotFound.js
import * as React from 'react';
import { useHistory } from 'react-router-dom';

const RouteNotFound = () => {
  const history = useHistory();
  return (
    <div>
      <button onClick={() => history.push('/help')} />
    </div>
  );
};

export default RouteNotFound;

 //NotFound.test.js
describe('RouteNotFound', () => {
  it('Redirects to correct URL on click', () => {
    const mockHistoryPush = jest.fn();

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

    const { getByRole } = render(
        <MemoryRouter>
          <RouteNotFound />
        </MemoryRouter>
    );

    fireEvent.click(getByRole('button'));
    expect(mockHistoryPush).toHaveBeenCalledWith('/help');
  });
})

但是 mockHistoryPush 没有被调用……我做错了什么?

原文由 Albert Alises 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 742
2 个回答

您实际上不需要模拟 react-router-dom (至少对于v5),因为它提供了一堆测试工具: https ://v5.reactrouter.com/web/guides/testing

要检查您的历史记录是否实际更改,您可以使用 createMemoryHistory 并检查其内容:

 import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Menu } from './Menu';
import { createMemoryHistory } from 'history'
import { Router } from 'react-router-dom';

test('triggers path change', () => {
  const history = createMemoryHistory();

  render(
    <Router history={history}>
      <Menu />
    </Router>
  );

  const aboutItem = screen.getByText('About');
  expect(aboutItem).toBeInTheDocument();

  userEvent.click(aboutItem);
  expect(history.length).toBe(2);
  expect(history.location.pathname).toBe('/about');
});

原文由 Soullivaneuh 发布,翻译遵循 CC BY-SA 4.0 许可协议

在模块范围内使用 jest.mock 将自动提升到代码块的顶部。这样您就可以在 NotFound.jsx 文件和您的测试文件中获得模拟版本 react-router-dom

此外,我们只想模拟 useHistory hook,所以我们应该使用 jest.requireActual() 来获取原始模块,其他方法保持原始版本。

这是解决方案:

NotFound.jsx

 import React from 'react';
import { useHistory } from 'react-router-dom';

const RouteNotFound = () => {
  const history = useHistory();
  return (
    <div>
      <button onClick={() => history.push('/help')} />
    </div>
  );
};

export default RouteNotFound;

NotFound.test.jsx :

 import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { render, fireEvent } from '@testing-library/react';
import RouteNotFound from './NotFound';

const mockHistoryPush = jest.fn();

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

describe('RouteNotFound', () => {
  it('Redirects to correct URL on click', () => {
    const { getByRole } = render(
      <MemoryRouter>
        <RouteNotFound />
      </MemoryRouter>,
    );

    fireEvent.click(getByRole('button'));
    expect(mockHistoryPush).toHaveBeenCalledWith('/help');
  });
});

100% 覆盖率的单元测试结果:

 PASS  src/stackoverflow/58524183/NotFound.test.jsx
  RouteNotFound
    ✓ Redirects to correct URL on click (66ms)

--------------|----------|----------|----------|----------|-------------------|
File          |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
--------------|----------|----------|----------|----------|-------------------|
All files     |      100 |      100 |      100 |      100 |                   |
 NotFound.jsx |      100 |      100 |      100 |      100 |                   |
--------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.133s, estimated 11s

源代码: https ://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58524183

原文由 slideshowp2 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进