测试是否已使用 Jest 调用 React prop 方法

Test that React prop method has been called with Jest

我有一个 Input 组件,它接受一个 prop 方法并在用户输入内容时调用它。代码本身按预期工作,但由于某些原因,测试失败。它认为没有调用 prop 方法。为什么会这样?出于测试目的,我使用 Jest 和 react-testing-library。

第二个问题。在实际应用中,我的想法是测试传递给该 prop 方法的参数。它是否被认为是实施测试(我知道我应该测试它)?

Input.js

export default function Input({ onChange }) {
  return <input onChange={onChange} />;
}

Test

import React from "react";
import { render, act, cleanup, fireEvent } from "react-testing-library";
import Input from "./input";

describe("Input tests", () => {
  afterEach(cleanup);

  it("Should call prop function", () => {
    const onChange = jest.fn();
    const { getByTestId } = render(<Input onChange={onChange} />);
    const input = getByTestId("input");

    act(() => {
      fireEvent.change(input, { target: { value: "Q" } });
    });

    expect(onChange).toHaveBeenCalled();
  });
});

https://codesandbox.io/s/y229669nvx

看了这个好像是by design to not assert against events handlers. Although it appears to work in React 16.5,但是用16.8.x就不行了。如果您想测试这些功能,我建议您转向酶。

使用 react-testing-library 的测试失败(但是,正如您会注意到的,当 运行 测试时,输入的值实际上会改变):https://codesandbox.io/s/n3rvy891n4

enzyme 测试成功:https://codesandbox.io/s/lx34ny41nl

您的测试不起作用的原因是您正在使用 getByTestId 来查找您的元素。 getByTestId 查找具有 data-testid 属性的 DOM 节点。

为了让你的测试通过,你有多种选择。

您可以将 data-testid 添加到您的 input<input data-testid="input" onChange={onChange} />。这会起作用,但是,最好尽可能避免测试 ID。

在真实的应用程序中,您的输入将使用 label 呈现,我们可以利用它:

const { getByLabelText } = render(
  <label>
    My input
    <Input onChange={onChange} />
  </label>
)
const input = getByLabelText('My input')

另一种解决方案是使用 container,它是 render 返回的值之一。它是一个 DOM 节点——就像 RTL 中的其他所有东西一样——所以你可以使用通常的 DOM API:

const { container } = render(<Input onChange={onChange} />)
// Any of these would work
const input = container.firstChild
const input = container.querySelector('input')

附带说明一下,我同意与 Enzyme 相比,RTL 测试似乎更复杂。这是有充分理由的。 RTL 促使您像测试黑盒一样测试您的应用程序。这在开始时有点难,但最终会带来更好的测试。

另一方面,Enzyme 默认情况下会模拟大多数内容,并允许您与组件实现进行交互。根据我的经验,这在开始时看起来更容易,但会产生脆弱的测试。

如果您需要入门帮助,我鼓励您加入 spectrum channel