toHaveValue returns null 而输入的值为 0

toHaveValue returns null while the input's value is 0

我正在为我的 React 项目编写测试代码。我要检查的是'if the input type is number, it disallow the text insertion'。下面是我写的测试代码。

it("disallow a text input", () => {
  const input = screen.getByLabelText(label0); // it has 0 as initial value
  const dummyText = "imyourfather";

  // typing a text won't change the value of input
  userEvent.type(input, dummyText);
  screen.debug();
  expect(input).toHaveValue(0); // FAILED -> return null
});

我在这里期望的是获得初始值 0 作为 toHaveValue 的结果。但实际上 returns null.

您可能会想“是的,您试图将文本插入到数字类型的输入中,这就是它 return 为空的原因”,但有趣的是 debug()console.log(input.value) return 0 如我所料。

<!-- the result of debug() -->
<div
  class="ui input"
>
  <input
    id="form-field-number01"
    required=""
    type="number"
    value="0"
  />
</div>

而且,如果您手动尝试将文本值插入浏览器中的数字输入,它实际上会显示初始值 0。任何人都知道为什么显示 toHaveValuedebug不同的结果?

经过一些挖掘,在 <input type="number"> 的情况下,这似乎确实是 toHaveValue 的预期行为。

首先,输入字符串时的输入值(在type="number"的情况下)实际上是一个empty string:

The value sanitization algorithm is as follows: If the value of the element is not a valid floating-point number, then set it to the empty string instead.

虽然 screen.debug() 将输出 DOM 树,但您可以在输入虚拟文本后通过记录它来检查实际的 value 属性:

userEvent.type(input, dummyText);
console.log('--> Value: ', input.value);
console.log('--> Value type: ', typeof input.value);

现在,jest-dom 用来获取输入值的函数看起来像 this:

function getInputValue(inputElement) {
  switch (inputElement.type) {
    case 'number':
      return inputElement.value === '' ? null : Number(inputElement.value)
    case 'checkbox':
      return inputElement.checked
    default:
      return inputElement.value
  }
}

如您所见,在 type="number" 的情况下,空字符串被解析为 null。不知道这背后的原因是什么。

对于您的具体情况,您可以测试输入元素,使其不将虚拟文本作为值或显示为空值:

expect(input).not.toHaveValue(dummyText);
expect(input).toHaveDisplayValue("");