首页 > 解决方案 > 未调用 React-testing-library 模拟函数

问题描述

我正在尝试测试我的组件:

在我的组件中,当我单击按钮时,我调用了一些函数并传递了一些 id。

我的测试:

it("should call function on submit click", async () => {
  const wrapper = render(<Component />);
   const id = "1";
  const handleSubmit = jest.fn();
  const SubmitBtn = wrapper.getByTestId("submit-btn");
  fireEvent.click(SubmitBtn);
  await waitFor(() => wrapper);
  expect(handleSubmit).toHaveBeenCalled();
});

在这里我试过:

expect(handleSubmit).toHaveBeenCalled();
expect(handleSubmit).toHaveBeenCalledWith(id);
expect(handleSubmit).toBeCalled();
expect(handleSubmit).toBeCalledWith(id)

尝试了一切,但它不起作用..

 expect(jest.fn()).toBeCalled()
    Expected number of calls: >= 1
    Received number of calls:    0

标签: jestjsreact-testing-library

解决方案


你的模拟不能被称为这个,因为你在渲染你的组件之后声明了它。我假设您的组件中有一个 handleSubmit 函数,该函数在提交单击时被调用,但是当您调用时:

const handleSubmit = jest.fn();

...该组件已经是渲染器,您无法模拟它的 handleSubmit 函数。

我的建议:

不要试图窥探 handleSubmit 函数,像真实用户一样测试

您不应该尝试测试内部组件逻辑,而是测试真实用户会看到的内容:加载微调器、确认消息……这就是促进 RTL 的原因,因为它会让您对测试充满信心,将您的测试与内部分离实现(这对于 React 组件单元测试来说是一件好事),并迫使您作为开发人员在编写代码时首先考虑用户(考虑如何使用 RTL 测试代码会迫使您考虑用户体验)。

在您的测试中,您可以这样做:

// in component
const handleSubmit = () => {
  // do things

  // say that this boolean controls a message display
  setSubmittedMessageDisplay(true);
}

测试中

it('should call function on submit click', async () => {
  const wrapper = render(<Component />);
  const submitBtn = wrapper.getByTestId('submit-btn');

  fireEvent.click(submitBtn);
  expect(wrapper.getByText('form submitted - controlled by submittedMessageDisplay')).toBeTruthy();
});

从父组件向下传递表单提交处理程序,模拟它

这意味着将事情提升到父组件:

// in parent
const handleSubmit = () => {...}
<ChildWithForm onSubmit={handleSubmit} />

// in child
<Form onSubmit={props.onSubmit}>...</Form>

然后在你的测试中你可以这样做:

test('submits form correctly', () => {
  const mockedHandler = jest.fn();
  const wrapper = render(<Child onSubmit={mockedHandler} />);

  const submitBtn = wrapper.getByTestId('submit-btn');
  fireEvent.click(submitBtn);

  expect(mockedHandler).toHaveBeenCalled();
});

推荐阅读