Enzyme报错:React HOC应为函数而非类,热键模拟测试遇阻
解决Enzyme测试HOC时的两个问题:组件类型错误与热键函数测试
一、先搞定"React HOC as a function not class"不变违规错误
从你给出的代码来看,你的HOC是一个接受组件并返回类组件的函数,最终导出的是Hoc(RealComponent)——也就是已经被包裹后的类组件。这个错误大概率是你在测试时误用了HOC函数本身,而不是它返回的包裹组件。
举个反例,如果你在测试里这么写就会报错:
import Hoc from './your-hoc-file'; import RealComponent from './real-component'; // 错误:直接把HOC函数当成组件传入shallow/mount const wrapper = shallow(Hoc);
正确的做法是:
- 确保你测试的是已经被HOC包裹后的最终组件——也就是你导出的
export default Hoc(RealComponent)。 - 在测试文件里直接导入这个导出的组件:
import WrappedRealComponent from './real-component-file'; // 这个就是已经被HOC包裹后的组件 const wrapper = shallow(<WrappedRealComponent />);
如果还是报错,检查你的HOC是否正确返回了类组件:确认HOC内部的类组件正确继承了React.Component,并且没有在返回时遗漏或者返回了其他值。
二、测试HOC内部的热键处理函数
接下来是热键测试的问题。因为热键逻辑是在HOC内部实现的,你需要模拟keyDown事件,并验证对应的处理函数是否被正确触发。这里分两种常见情况:
情况1:HOC给包裹组件传递了热键相关的props
如果你的HOC是把热键处理函数作为props传给了RealComponent,那你可以直接从wrapper里获取props,然后模拟调用,或者触发事件后检查props函数是否被调用:
import WrappedRealComponent from './real-component-file'; import sinon from 'sinon'; // 用sinon做函数存根,用jest.mock也可以 test('triggers hotkey handler on Ctrl+Enter', () => { // 创建一个存根函数替代热键处理逻辑 const mockHotkeyHandler = sinon.spy(); // 如果HOC允许传入自定义处理函数,直接通过props传递 const wrapper = shallow(<WrappedRealComponent handleHotkey={mockHotkeyHandler} />); // 模拟Ctrl+Enter的keyDown事件 wrapper.simulate('keyDown', { key: 'Enter', ctrlKey: true, preventDefault: () => {} // 模拟preventDefault方法,避免控制台报错 }); // 验证存根函数是否被触发 expect(mockHotkeyHandler.calledOnce).toBe(true); });
情况2:热键逻辑完全封装在HOC内部(未暴露给子组件)
如果HOC内部自己在生命周期里给document/window绑定了keyDown监听,那你需要直接模拟全局的keyDown事件,且建议用mount而非shallow(shallow不会执行组件生命周期,无法触发事件绑定):
import WrappedRealComponent from './real-component-file'; import sinon from 'sinon'; test('triggers internal hotkey handler on keyDown', () => { // 挂载组件,让HOC执行生命周期绑定事件 const wrapper = mount(<WrappedRealComponent />); // 获取HOC实例,存根内部的处理函数 const hocInstance = wrapper.instance(); sinon.spy(hocInstance, 'handleHotkey'); // 模拟全局keyDown事件(比如Ctrl+S) const keyDownEvent = new KeyboardEvent('keydown', { key: 's', ctrlKey: true, bubbles: true // 确保事件能被监听到 }); document.dispatchEvent(keyDownEvent); // 验证HOC内部的处理函数是否被调用 expect(hocInstance.handleHotkey.calledOnce).toBe(true); // 清理存根与组件 hocInstance.handleHotkey.restore(); wrapper.unmount(); });
额外注意事项
- 确保Enzyme版本和React版本兼容,比如React 17+需要使用
@wojtekmaj/enzyme-adapter-react-17这类适配包,版本不兼容也可能引发奇怪的错误。 - 如果你的HOC是带配置参数的高阶函数(比如
Hoc(config)(RealComponent)),测试时要确保正确调用所有层级,拿到最终的包裹组件。
内容的提问来源于stack exchange,提问作者Phil Lucks
相关产品推荐
相关产品推荐

