如何在Enzyme/Jest中测试useEffect内的ESC键关闭模态框逻辑
如何正确测试React模态框的ESC键关闭逻辑
首先,我们来拆解你当前测试代码存在的核心问题:
- 你用
jest.fn()替换了global.document.addEventListener,这直接导致组件里useEffect中定义的实际键盘监听器没有真正绑定到document上。后续触发dispatchEvent时,根本没有对应的回调函数执行,自然无法触发toggleShowModal。 - 通过
jest.spyOn(wrapper.props(), 'toggleShowModal')监听props方法的方式不够可靠,mount后的组件props引用可能和你最初传入的mock函数存在差异,导致监听失效。
下面是修正后的测试方案,能准确验证ESC键关闭模态框的逻辑:
import { mount } from 'enzyme'; import Modal from './Modal'; // 替换为你的Modal组件实际路径 test('triggers toggleShowModal when ESC key is pressed', () => { // 1. 创建一个可追踪的mock函数 const mockToggleShowModal = jest.fn(); // 2. 挂载组件并传入mock函数作为props const wrapper = mount(<Modal toggleShowModal={mockToggleShowModal} />); // 3. 构造ESC键的keydown事件,确保事件能冒泡到document const escKeyEvent = new KeyboardEvent('keydown', { key: 'Escape', keyCode: 27, which: 27, bubbles: true }); // 4. 在document上触发该键盘事件 document.dispatchEvent(escKeyEvent); // 5. 断言mock函数被成功调用 expect(mockToggleShowModal).toHaveBeenCalled(); // 可选验证:卸载组件后,监听器会被移除,不会重复触发 wrapper.unmount(); const secondEscEvent = new KeyboardEvent('keydown', { key: 'Escape' }); document.dispatchEvent(secondEscEvent); expect(mockToggleShowModal).toHaveBeenCalledTimes(1); });
另外,也建议你优化组件代码,让逻辑更严谨:
import React from 'react'; const Modal = ({ toggleShowModal }) => { const ESCAPE_KEY_CODE = 27; React.useEffect(() => { const handleEscKey = (e) => { // 简化判断逻辑,key是现代浏览器标准,keyCode/which做兼容 if (e.key === 'Escape' || e.keyCode === ESCAPE_KEY_CODE) { toggleShowModal(); } }; document.addEventListener('keydown', handleEscKey); // 清理函数确保组件卸载时移除监听器,避免内存泄漏 return () => document.removeEventListener('keydown', handleEscKey); }, [toggleShowModal]); // 加入依赖项,遵循React Hooks规则 return ( <div className="modal-container"> {/* 模态框内容 */} </div> ); }; export default Modal;
几个关键注意事项:
- 不要mock原生的
addEventListener:让组件正常绑定监听器,才能真实模拟用户的键盘操作流程。 - 事件需设置
bubbles: true:确保键盘事件能正确冒泡到document层级,被我们的监听器捕获。 - 完善useEffect的依赖数组:将
toggleShowModal加入依赖项,避免不必要的重渲染和逻辑异常。
内容的提问来源于stack exchange,提问作者Yuridia Larios Aispuro
相关产品推荐
相关产品推荐

