如何测试由反应测试库中的 onChange 处理程序更新的道具?

How to test props that are updated by an onChange handler in react testing library?

我在输入上有一个 onChange 处理程序,我正在尝试根据我在 Dom 测试库文档 here and here.

中阅读的内容进行测试

我的代码中的一个不同之处在于,我没有使用本地状态来控制输入值,而是使用了道具。所以 onChange 函数实际上是在调用另一个函数(也是通过 props 接收到的),它将 "lifted up" 的状态更新到另一个组件。最终,组件接收输入值作为 prop 并更新输入值。

我正在模拟道具并尝试做一些简单的测试来证明 onChange 处理程序按预期工作。

我希望更改处理程序中调用的函数被调用的次数与测试中使用的 fireEvent.change 的次数相同,这适用于:

const { input } = setup();
fireEvent.change(input, { target: { value: "" } });
expect(handleInstantSearchInputChange).toHaveBeenCalledTimes(1);

我希望 input.value 是从原始模拟道具设置中读取的,并且适用于:

  const { input } = setup();
  expect(input.value).toBe("bacon");

但是,我在做一些愚蠢的事情(似乎根本不了解模拟函数),我不明白为什么下面的块没有更新input.value,并继续从原始模拟道具设置中读取 input.value 设置。

这失败并期待“”/收到"bacon" <= set in original prop

fireEvent.change(input, { target: { value: "" } });
expect(input.value).toBe("");

问题:如何编写测试来证明 input.value 已根据以下代码更改?我假设我需要模拟 handleInstantSearchInputChange 函数来做某事,但我真的不知道我在这里做什么。

感谢您提供有关如何and/or更好地理解这一点的任何建议。

测试文件

import React from "react";
import InstantSearchForm from "../../components/InstantSearchForm";
import { render, cleanup, fireEvent } from "react-testing-library";

afterEach(cleanup);

let handleInstantSearchInputChange, props;
  handleInstantSearchInputChange = jest.fn();
  props = {
    foodSearch: "bacon",
    handleInstantSearchInputChange: handleInstantSearchInputChange
  };

const setup = () => {
  const utils = render(<InstantSearchForm {...props} />);
  const input = utils.getByLabelText("food-search-input");
  return {
    input,
    ...utils
  };
};

it("should render InstantSearchForm correctly with provided foodSearch prop", () => {
  const { input } = setup();
  expect(input.value).toBe("bacon");
});

it("should handle change", () => {
  const { input } = setup();
  fireEvent.change(input, { target: { value: "" } });
  expect(input.value).toBe("");
  fireEvent.change(input, { target: { value: "snickerdoodle" } });
  expect(input.value).toBe("snickerdoodle");
});

组件

import React from "react";
import PropTypes from "prop-types";

const InstantSearchForm = props => {
  const handleChange = e => {
    props.handleInstantSearchInputChange(e.target.value);
  };
  return (
    <div className="form-group">
      <label className="col-form-label col-form-label-lg" htmlFor="food-search">
        What did you eat, fatty?
      </label>
      <input
        aria-label="food-search-input"
        className="form-control form-control-lg"
        onChange={handleChange}
        placeholder="e.g. i ate bacon and eggs for breakfast with a glass of whole milk."
        type="text"
        value={props.foodSearch}
      />
    </div>
  );
};

InstantSearchForm.propTypes = {
  foodSearch: PropTypes.string.isRequired,
  handleInstantSearchInputChange: PropTypes.func.isRequired
};

export default InstantSearchForm;

您考虑测试的方式有点不正确。该组件的行为纯粹如下:

  1. 当将文本作为道具传递时 foodSearch 会正确呈现它。
  2. 组件在更改时调用适当的处理程序。

所以只测试上面的内容。

change 事件触发后 foodSearch 属性发生的变化不是该组件(InstantSearchForm)的责任。该责任在于处理该状态的方法。因此,您可能希望将该处理程序方法专门作为单独的测试进行测试。