如何使用 Enzyme 测试 onKeyPress 事件处理程序

How to test onKeyPress event handler with Enzyme

我有一个触发 onKeyPress 事件的测试:

    const wrapper = mount(wrapper);

    wrapper
      .find('[data-test="test-number-input"]')
      .find("input")
      .simulate("keypress", { target: { value: "2" }, key: 2 });

这工作正常,但不会触发组件中的 onChange 事件(与浏览器中的 运行 不同)。据我了解,这种行为在 Enzyme 中是有意为之的。那么问题是我无法读取新值,因为状态是在 onChange 处理程序中设置的。那么测试我的 keyPress 处理程序行为的最佳方法是什么?

import React from "react";
import TextField from "@material-ui/core/TextField";

export default (props) => {
  const minValue = props.minValue ?? 0;
  const maxValue = props.maxValue ?? 100;
  const step = props.step ?? 1;

  const handleKeyPress = (evt) => {
    const enteredCharCode = evt.which ? evt.which : evt.keyCode;
    const newValue = evt.target.value + evt.key;

    if (
      enteredCharCode <= 47 ||
      enteredCharCode >= 58 ||
      newValue < minValue ||
      newValue > maxValue
    ) {
      evt.preventDefault();
    }
  };

  const handleChange = (evt) => {
    if (evt.target.value[0] === "0" && evt.target.value.length > 1) {
      /* Prevent input if the first character is zero and the entered character is also zero.
           else remove the first zero. */
      (evt.which ? evt.which : evt.keyCode) === 48
        ? evt.preventDefault()
        : (evt.target.value = evt.target.value.slice(1));
    } else {
      props.onChange(evt);
    }
  };

  return (
    <TextField
      name={props.name}
      label={props.labelText}
      type="number"
      defaultValue={props.defaultValue}
      inputProps={{
        min: minValue,
        max: maxValue,
        step: step,
      }}
      onKeyPress={handleKeyPress}
      onChange={handleChange}
      data-test="test-number-input"
    />
  );
};

虽然在我看来这不是一个理想的解决方案,但我决定遵循这个 https://medium.com/@acesmndr/testing-react-functional-components-with-hooks-using-enzyme-f732124d320a 并将事件处理程序方法移到组件函数之外:

import React from "react";
import TextField from "@material-ui/core/TextField";

export const handleKeyPress = (evt, minValue, maxValue) => {
  const enteredCharCode = evt.which ? evt.which : evt.keyCode;
  const newValue = evt.target.value + evt.key;

  if (
    enteredCharCode <= 47 ||
    enteredCharCode >= 58 ||
    newValue < minValue ||
    newValue > maxValue
  ) {
    evt.preventDefault();
    return;
  }
  return newValue;
};

export default (props) => {
  const minValue = props.minValue ?? 0;
  const maxValue = props.maxValue ?? 100;
  const step = props.step ?? 1;

  const handleChange = (evt) => {
    if (evt.target.value[0] === "0" && evt.target.value.length > 1) {
      /* Prevent input if the first character is zero and the entered character is also zero.
           else remove the first zero. */
      (evt.which ? evt.which : evt.keyCode) === 48
        ? evt.preventDefault()
        : (evt.target.value = evt.target.value.slice(1));
    } else {
      props.onChange(evt);
    }
  };

  return (
    <TextField
      name={props.name}
      label={props.labelText}
      type="number"
      defaultValue={props.defaultValue}
      inputProps={{
        min: minValue,
        max: maxValue,
        step: step,
      }}
      onKeyPress={(evt) => handleKeyPress(evt, minValue, maxValue)}
      onChange={handleChange}
      data-test="test-number-input"
    />
  );
};

所以现在我可以像这样测试事件处理程序:

expect(
      handleKeyPress(
        {
          target: { value: "5" },
          key: 2,
          preventDefault: () => {},
        },
        1,
        100
      )
    ).toBe("52");

    expect(
      handleKeyPress(
        {
          target: { value: "99" },
          key: 2,
          preventDefault: () => {},
        },
        1,
        100
      )
    ).toBe(undefined);