我目前有一个使用onChange
方法的react组件。
我想测试onChange方法,例如是否有人键入或粘贴内容。问题是handleChange
依赖于使用它的父组件。测试模拟的最佳方法是什么?我是否需要引用父组件的handleChange
方法并进行模拟?
CodeSandbox(我没有在此处添加测试)
https://codesandbox.io/s/react-basic-example-cwdh1?from-embed
更新的当前测试:
const handleChange = jest.fn();
const initProps = {
name: "Title",
label: "Body",
type: "text",
value: "",
handleChange
};
describe("TextBox", () => {
let wrapper;
beforeEach(() => {
wrapper = mount(<TextBox {...props} />);
});
afterEach(() => {
// resets the mocked fn after each test
handleChange.mockClear();
});
it("should call handleChange with a new value", () => {
const value = "testing input";
wrapper.find("input").simulate("change", { target: { value } });
expect(handleChange).toHaveBeenCalledWith(value);
});
});
错误:
Expected: "testing input"
Received: {"_dispatchInstances": null, "_dispatchListeners": null,
"_targetInst": ......more fields... "nativeEvent": {"target": <input … />,
"type": "change"}, "target": {"value": "testing input"}, "timeStamp":
1576040322012, "type": "change"}
我知道我收到此错误,因为该值来自表单域。有什么方法可以提取目标字段?
答案 0 :(得分:1)
我认为您对测试方法有些困惑。当您实际拥有的是一个单独的可重用{{1}时,您要尝试的是使用父子组件进行组件/集成测试(操纵父类字段以更新孩子的value
道具)。 }没有父级的子级组件,需要进行单元测试。
因此,您有两种选择:
选项1:安装父组件并操纵其类字段以更新此子组件(和/或操纵子事件处理程序道具,然后再更新父组件的状态...,依此类推)。这将测试 ONE 特定组件的父代与子代之间的同步性。这对于测试管理TextBox
并将其分配给某些子(form
)组件的组件(例如state
)特别有用。
选项2:浅入/挂接子组件并操纵其事件处理程序以触发开玩笑的模拟父项(例如,操纵输入的form elements
道具并期望它以a调用模拟父项onChange
道具。 handleChange
)。它实际上并没有更新子级,而是对其进行了模拟。这对于测试可以具有许多不同父组件的 SHARED 可重用子组件特别有用。
可供选择的选项会因开发人员和项目以及项目而异。但是在理想情况下,您的测试套件将遵循类似于“测试金字塔”的内容:
对于您而言,我建议如果该子组件与您的应用程序中的许多父组件共享,那么请同时进行父集成测试和子单元测试(这将导致一些重叠的测试,但要确保跨子组件的兼容性)应用程序(如果父母或孩子要更改或更新)。如果仅在单个父组件中重用此组件,则只需执行单个父集成测试。就是说,这只是我的建议-不规则!
另外,您的value
组件不使用状态,因此您可以简单地使用无状态函数来代替类,而无需使用类:
TextBox
以下是如何测试此组件的示例:
一些注意事项:
您的const TextBox = ({ value, type, handleChange }) => (
<Form.Control
type={type}
value={value}
onChange={handleChange}
/>
);
本质上是第三方组件,大概已经由TextBox
维护人员进行了测试。因此,从实际的角度来看,为此子组件创建测试是多余的。相反,我建议测试父组件,并期望在更改此子TextBox的react-bootstrap
时更新父组件的状态。但是,codeandbox包含针对input
和TextBox
组件的测试。
关于为什么您的Form
模拟函数被多个道具调用的原因……它被Synthetic Event调用,这是正常现象(我的大脑屁没有考虑到这一点)。就是说,您可以通过遍历expect.objectContaining数组或通过针对handleChange
本身断言来使用mockedFn.mock.calls来断言mockedFn
测试中的全部事件。 )。