使用 React 测试库在 React 中断言表单提交的道具调用
Asserting prop call for form submit in React using React Testing Library
您可以在以下代码和框中重现该问题:
例如,我制作了一个组件,它使用以下代码在每次单击表单按钮时获取随机图像:
import { Button } from "antd";
...
class ContinuousMemeDeliveryApi extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
static defaultProps = { getImage };
state = { image: images[0], random: 0 };
handleClick = async e => {
e.preventDefault();
const { data } = await this.props.getImage();
this.setState({ image: data.image, random: data.random });
};
...
render() {
return (
<form onSubmit={this.handleClick}>
<Button htmlType="submit">Click Me</Button>
...
</form>
);
}
这按预期工作,我编写了以下代码来测试实现:
test("loads random memes on click", async () => {
const mockGetImage = jest.fn(() =>
Promise.resolve({ data: { image: "testImage.jpg" } })
);
const { getByText } = render(
<ContinuousMemeDeliveryApi getImage={mockGetImage} />
);
const clickMeButton = getByText(/click/i);
fireEvent.click(clickMeButton);
// @TODO: fix assertion
expect(mockGetImage).toHaveBeenCalledTimes(1);
});
但是测试失败并显示以下错误消息:
expect(jest.fn()).toHaveBeenCalledTimes(1)
Expected mock function to have been called one time, but it was called zero times.
关于失败原因的任何想法?
由于您在同一文档(您的应用程序和测试)中有 2 个反应根呈现,因此您不能使用默认 document.body
作为反应测试库的基本元素。
使用当前的方法,您的查询实际上是在您的应用程序中找到元素,而不是在呈现的测试中,因为它们绑定到 baseElement = document.body
而您的 div#container
排在第一位。这就是为什么 mock 根本没有被调用的原因。
您可以添加额外的容器来隔离测试 DOM 树
// index.html
<div id="test-container"></div>
现在您可以在渲染测试时指定容器
import { render as rtlRender, fireEvent, wait } from "react-testing-library";
// get the container
const container = document.getElementById('test-container')
// override render to provide custom container
const render = (ui, options = {}) => rtlRender(ui, { container, ...options })
您可以在以下代码和框中重现该问题:
例如,我制作了一个组件,它使用以下代码在每次单击表单按钮时获取随机图像:
import { Button } from "antd";
...
class ContinuousMemeDeliveryApi extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
static defaultProps = { getImage };
state = { image: images[0], random: 0 };
handleClick = async e => {
e.preventDefault();
const { data } = await this.props.getImage();
this.setState({ image: data.image, random: data.random });
};
...
render() {
return (
<form onSubmit={this.handleClick}>
<Button htmlType="submit">Click Me</Button>
...
</form>
);
}
这按预期工作,我编写了以下代码来测试实现:
test("loads random memes on click", async () => {
const mockGetImage = jest.fn(() =>
Promise.resolve({ data: { image: "testImage.jpg" } })
);
const { getByText } = render(
<ContinuousMemeDeliveryApi getImage={mockGetImage} />
);
const clickMeButton = getByText(/click/i);
fireEvent.click(clickMeButton);
// @TODO: fix assertion
expect(mockGetImage).toHaveBeenCalledTimes(1);
});
但是测试失败并显示以下错误消息:
expect(jest.fn()).toHaveBeenCalledTimes(1)
Expected mock function to have been called one time, but it was called zero times.
关于失败原因的任何想法?
由于您在同一文档(您的应用程序和测试)中有 2 个反应根呈现,因此您不能使用默认 document.body
作为反应测试库的基本元素。
使用当前的方法,您的查询实际上是在您的应用程序中找到元素,而不是在呈现的测试中,因为它们绑定到 baseElement = document.body
而您的 div#container
排在第一位。这就是为什么 mock 根本没有被调用的原因。
您可以添加额外的容器来隔离测试 DOM 树
// index.html
<div id="test-container"></div>
现在您可以在渲染测试时指定容器
import { render as rtlRender, fireEvent, wait } from "react-testing-library";
// get the container
const container = document.getElementById('test-container')
// override render to provide custom container
const render = (ui, options = {}) => rtlRender(ui, { container, ...options })