React 16:使用Jest和Enzyme测试handleChange事件报错解决
问题:Jest+Enzyme测试React组件handleChange事件时触发TypeError
在测试React组件下拉按钮点击触发的handleChange事件时,出现错误TypeError: Cannot read property 'attributes' of undefined,相关代码及报错如下:
组件代码(Component.js)
handleChange = event => { if (event.target.attributes["value"]) { window.dataLayer.push({ event: "customEvent", category: "dropdown", action: "select", label: "ABC", attribute1: "attribute1Value", attribute2: "attribute2Value", attribute3: "attribute3Value", attribute4: event.target.attributes["value"].value.toLowerCase() }); this.setState({ stateName: event.target.attributes["value"].value }); } };
测试代码(Component.test.js)
it.only("should call handleChange reponse", () => { const handleChange = jest.fn(); const wrapper = shallow( <ComponentName triggerRequest={{ triggers: { coverage: "ABC" } }} /> ); wrapper.find(".dropdown").simulate("click"); wrapper.instance().handleChange({}); expect(handleChange.mock.calls.length).toBe(1); // expect(handleChange).toHaveBeenCalled(); });
报错信息
TypeError: Cannot read property 'attributes' of undefined 213 | 214 | handleChange = event => { > 215 | if (event.target.attributes["value"]) { | ^ 216 | window.dataLayer.push({ 217 | event: "custom_event", 218 | category: "dropdown",
问题原因
- 事件对象不完整:测试中直接传入
{}作为event参数,该对象没有target属性,导致event.target为undefined,访问event.target.attributes时触发报错。 - 测试逻辑错误:自定义的
handleChange = jest.fn()没有替换组件实例的同名方法,测试中实际调用的是组件原生的handleChange,因此expect(handleChange.mock.calls.length).toBe(1)永远不会成立。
解决方法
1. 构造合法的事件对象
调用handleChange时,传入包含target和attributes结构的模拟事件对象:
const mockEvent = { target: { attributes: { value: { value: "TEST_VALUE" } } } };
2. 正确监听组件的handleChange方法
用jest.spyOn监听组件实例的handleChange方法,替代自定义的空jest.fn:
const wrapper = shallow(<ComponentName ...props />); const handleChangeSpy = jest.spyOn(wrapper.instance(), 'handleChange'); // React 16+类组件需强制更新,确保spy生效 wrapper.instance().forceUpdate();
3. 修正后的完整测试代码
it.only("should call handleChange correctly", () => { // 构造模拟事件对象 const mockEvent = { target: { attributes: { value: { value: "TEST_VALUE" } } } }; const wrapper = shallow( <ComponentName triggerRequest={{ triggers: { coverage: "ABC" } }} /> ); // 监听组件的handleChange方法 const handleChangeSpy = jest.spyOn(wrapper.instance(), 'handleChange'); wrapper.instance().forceUpdate(); // 触发方法 wrapper.instance().handleChange(mockEvent); // 若点击事件会绑定调用handleChange,也可改用: // wrapper.find(".dropdown").simulate("click", mockEvent); // 断言方法被调用 expect(handleChangeSpy).toHaveBeenCalledTimes(1); // 可选:断言传入的参数是否正确 expect(handleChangeSpy).toHaveBeenCalledWith(mockEvent); });
4. 优化组件代码(可选,避免生产环境报错)
在组件的handleChange中添加空值判断,防止实际场景中event或event.target为undefined的情况:
handleChange = event => { if (event?.target?.attributes?.["value"]) { // 原逻辑代码 } };
内容的提问来源于stack exchange,提问作者Tapesh Patel
相关产品推荐
相关产品推荐

