使用React Testing库在React中声明表单提交的道具调用

时间:2019-01-21 10:28:13

标签: javascript reactjs unit-testing jestjs react-testing-library

您可以在以下代码和框中重现该问题:

Edit Continuous Meme Delivery

作为示例,我制作了一个组件,每次单击表单按钮时,该组件使用以下代码获取随机图像:

import { Button } from "antd";
...
class ContinuousMemeDeliveryApi extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  static defaultProps = { getImage };
  state = { image: images[0], random: 0 };

  handleClick = async e => {
    e.preventDefault();
    const { data } = await this.props.getImage();
    this.setState({ image: data.image, random: data.random });
  };
  ...
  render() {
    return (
      <form onSubmit={this.handleClick}>
        <Button htmlType="submit">Click Me</Button>
        ...
      </form>
    );
  }

这可以按预期工作,并且我编写了以下代码来测试实现:

test("loads random memes on click", async () => {
  const mockGetImage = jest.fn(() =>
    Promise.resolve({ data: { image: "testImage.jpg" } })
  );
  const { getByText } = render(
    <ContinuousMemeDeliveryApi getImage={mockGetImage} />
  );

  const clickMeButton = getByText(/click/i);

  fireEvent.click(clickMeButton);
  // @TODO: fix assertion
  expect(mockGetImage).toHaveBeenCalledTimes(1);
});

但是测试失败并显示以下错误消息:

expect(jest.fn()).toHaveBeenCalledTimes(1)

Expected mock function to have been called one time, but it was called zero times.

关于失败的任何想法?

1 个答案:

答案 0 :(得分:1)

由于在同一文档(您的应用程序和测试)中有2个反应根渲染,因此不能使用默认的document.body作为反应测试库的基础元素。

使用当前方法,您的查询实际上在应用程序中找到的元素不在呈现的测试中,因为它们绑定到baseElement = document.body且您的div#container在前。这就是为什么根本不调用模拟的原因。

Working Example

您可以添加其他容器来隔离测试DOM树

// index.html
<div id="test-container"></div>

现在,您可以在呈现测试时指定容器

import { render as rtlRender, fireEvent, wait } from "react-testing-library";

// get the container
const container = document.getElementById('test-container')

// override render to provide custom container
const render = (ui, options = {}) => rtlRender(ui, { container, ...options })