如何用Jest覆盖React中含可选链函数的catch代码块?
问题分析与解决方案
核心问题根源
- 模块级执行时机冲突:原代码在模块加载阶段直接调用了
useNavigateMFE(),导致测试用例中mock的useNavigate在模块初始化后才生效,错过了第一次执行逻辑的时机。 - 断言逻辑错误:测试中
expect(consoleSpy).toHaveBeenCalledWith(expect.any(Error))与实际代码中console.log("An error occurred:", e)的参数不匹配,即使触发catch块也会断言失败。 - 未确保进入
useNavigate分支:测试时未正确设置window.hfe状态,可能没有触发走useNavigate()的分支,自然不会触发mock的错误。
解决方案
方案一:重构代码为合规的React Hook(推荐)
将useNavigateMFE改为符合React Hook规则的自定义Hook,确保每次组件渲染时重新执行逻辑,同时避免模块级执行的问题:
import { useNavigate } from 'react-router-dom'; export function useNavigateMFE() { let navigate; try { // 确保进入useNavigate分支的条件:window.hfe.testdevice不存在/为false navigate = window?.hfe?.testdevice ? window?.hfe?.histr : useNavigate(); } catch (e) { console.log("An error occurred:", e); // 添加回退逻辑,避免navigate为undefined navigate = () => {}; } return navigate; }
组件中使用方式:
const navigate = useNavigateMFE();
对应的测试用例:
import { useNavigate } from 'react-router-dom'; import { useNavigateMFE } from './path-to-your-module'; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useNavigate: jest.fn(() => { throw new Error("Mocked error"); }), })); describe('useNavigateMFE', () => { beforeEach(() => { // 重置window状态,确保进入useNavigate分支 delete window.hfe; }); it('should enter catch block when useNavigate throws error', () => { const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); // 调用Hook(需在React测试环境中,可搭配@testing-library/react) useNavigateMFE(); // 修正断言,匹配实际console.log的参数 expect(consoleSpy).toHaveBeenCalledWith("An error occurred:", expect.any(Error)); consoleSpy.mockRestore(); }); });
方案二:针对现有代码调整测试逻辑
如果无法修改原代码,通过清除模块缓存确保mock生效:
describe('useNavigateMFE', () => { beforeEach(() => { // 清除模块缓存,确保每次测试重新加载模块 jest.resetModules(); // 重置window状态,触发useNavigate分支 delete window.hfe; }); it('should trigger catch block on useNavigate error', () => { // 提前mock react-router-dom jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), useNavigate: jest.fn(() => { throw new Error("Mocked error"); }), })); const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); // 重新导入模块,触发模块级的useNavigateMFE调用 require('./path-to-your-module'); // 断言console.log的正确参数 expect(consoleSpy).toHaveBeenCalledWith("An error occurred:", expect.any(Error)); consoleSpy.mockRestore(); }); });
内容的提问来源于stack exchange,提问作者max
相关产品推荐
相关产品推荐

