测试是否已使用 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();
});
});
看了这个好像是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。
我有一个 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();
});
});
看了这个好像是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。