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

时间:2019-02-01 12:44:56

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

我正在尝试根据Dom测试库文档herehere中阅读的内容来测试输入的onChange处理程序。

我的代码中的一个区别是,我使用props而不是使用局部状态来控制输入值。因此,onChange函数实际上是在调用另一个函数(也通过props接收),该函数将已“提升”到另一个组件的状态更新。最终,输入的值由组件作为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设置。

此操作失败,并期望在原始道具中设置“” /收到“培根” <=

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

问题:如何编写测试以证明给定以下代码,input.value已更改?我以为我需要模拟 handleInstantSearchInputChange 函数来执行某项操作,但是我现在还真的不知道自己在做什么。

感谢您提供有关如何操作和/或更好地理解这一点的建议。

测试文件

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 个答案:

答案 0 :(得分:1)

您考虑测试的方式略有错误。该组件的行为纯粹是以下情况:

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

所以只能测试以上内容。

触发变更事件后foodSearch道具发生的事情不是该组件(InstantSearchForm)的责任。责任在于处理该状态的方法。因此,您将需要专门测试该处理程序方法作为单独的测试。