问题描述
我连最简单的 react jsonschema form 测试都写不出来。因为对输入元素的更改似乎没有反映在 dom 中。
给出这样的最小形式:
const schema = {
title: "Todo",type: "object",properties: {
title: { type: "string",title: "Title",default: "A new task" }
}
};
const formData = { title: "First task aaa" };
export class MyForm extends React.Component {
render() { return <Form schema={schema} formData={formData} />; }
}
一个最小的测试看起来像
test("changes input",async () => {
render(<MyForm />);
const input = screen.getByRole("textBox");
expect(input.value).toBe("First task aaa");
await userEvent.type(input,"567890",{ delay: 10 });
expect(input.value).toBe("567890");
});
(在 Codesandbox 完成示例。)
在表单字段中输入后,文本 First task aaa
应替换为 567890
。不幸的是,它不是。input.value
保留值 First task aaa
。
我隐藏了许多触发事件和等待结果的变体,但输入元素的值始终保持不变。
测试 <MyForm />
组件时我缺少什么?对我来说似乎很标准。
解决方法
我也可以重现您的问题,看起来 react-jsonschema-form 与 fireEvent
或 userEvent
的配合不佳。
但是,使用 react-doms Simulate 函数,它确实有效:
import React from "react";
import { Simulate } from 'react-dom/test-utils'
import { render } from "@testing-library/react";
import { MyForm } from "./form.js";
// Tests in codesandbox fail in Safari - use Firefox or Chrome
// click on the "Tests" tab in the upper right.
test("changes input",async () => {
const { getByLabelText } = render(<MyForm />);
const input = getByLabelText("Title");
expect(input.value).toBe("First task aaa");
Simulate.change(input,{ target: { value: '567890' }})
expect(input.value).toBe("567890");
});
,
就您的 UI 使用 fluent-ui
表单库而言,这会将输入值与您的 formData.title
字段绑定。这可能会中断 userEvent.type
操作。为了简单地测试 userEvent.type
功能,您可以使用纯输入元素制作表单组件,并将您的默认值绑定为输入元素的 defaultValue。
例如:
export class MyForm extends React.Component {
render() {
return <input type="text" defaultValue="First task aaa" />;
}
}
如果您会在测试输出中看到以下错误:
expect(element).toHaveValue(567890)
Expected the element to have value:
567890
Received:
First task aaa567890
13 | expect(input).toHaveValue("First task aaa");
14 | userEvent.type(input,'567890');
> 15 | expect(input).toHaveValue('567890');
| ^
16 | });
如您所见,userEvent.type
会将附加输入附加到当前值。因此,您可以只使用 Simulate.change
功能或在 userEvent.clear
行之前使用 userEvent.type
功能,如下所示。
test("changes input",async () => {
render(<MyForm />);
const input = screen.getByRole("textbox");
expect(input).toHaveValue("First task aaa");
userEvent.clear(input);
userEvent.type(input,"567890");
expect(input).toHaveValue("567890");
});
此答案可能对您的问题有所帮助。
干杯!