Jest中Mock React Hook useScrollDetect跳过节流即时触发滚动回调
Jest单元测试Mock useScrollDetect移除节流逻辑方案
不需要Mock lodash.throttle,直接替换整个useScrollDetect的模块实现即可,完全绕开内部节流逻辑,同时保持Hook对外调用签名不变,不影响上层Hook的正常调用逻辑。
核心实现
在测试文件中直接Mock use-scroll-detect 模块,重写Hook逻辑,直接绑定原始传入的onScroll回调到window滚动事件,跳过所有throttle包装步骤。
文件级Mock(最常用)
在测试文件顶部写入以下Mock代码,路径替换为你项目中use-scroll-detect.ts的实际相对路径:
import type { useScrollDetect } from './use-scroll-detect'; jest.mock('./use-scroll-detect', () => { const actualReact = require('react'); return { useScrollDetect: ( onScroll: (e: Event) => void, _throttleTime = 100, enable = true ) => { actualReact.useEffect(() => { if (!enable) return; // 直接绑定原始回调,无节流逻辑 const scrollHandler = (e: Event) => onScroll(e); window.addEventListener('scroll', scrollHandler, { passive: true }); return () => { window.removeEventListener('scroll', scrollHandler); }; }, [onScroll, enable]); } } as { useScrollDetect: typeof useScrollDetect }; });
单用例动态Mock
如果需要在部分用例中保留原Hook逻辑、部分用例使用Mock版本,可以用动态Mock配合模块重置实现:
test('滚动触发逻辑无节流延迟', () => { jest.resetModules(); jest.doMock('./use-scroll-detect', () => { const actualReact = require('react'); return { useScrollDetect: (onScroll: (e: Event) => void, _throttleTime = 100, enable = true) => { actualReact.useEffect(() => { if (!enable) return; const scrollHandler = (e: Event) => onScroll(e); window.addEventListener('scroll', scrollHandler, { passive: true }); return () => window.removeEventListener('scroll', scrollHandler); }, [onScroll, enable]); } }; }); // 动态Mock完成后再引入上层Hook,确保依赖被正确替换 const { useYourTargetHook } = require('./your-upper-hook'); // 后续正常执行测试逻辑 });
测试用例示例
配合@testing-library/react做Hook测试时,不需要加任何等待时间,触发滚动事件后可以立即断言回调执行:
import { renderHook } from '@testing-library/react'; // 提前执行上述Mock逻辑 test('滚动事件触发后回调立即执行', () => { const mockScrollCallback = jest.fn(); // 渲染依赖useScrollDetect的上层Hook renderHook(() => useYourTargetHook({ onScroll: mockScrollCallback })); // 触发window滚动事件 window.dispatchEvent(new Event('scroll')); // 无需waitFor、无需延迟等待,直接断言通过 expect(mockScrollCallback).toHaveBeenCalledTimes(1); });
注意事项
- Mock时在函数内部用
require引入React,不要在Mock块外部直接import,避免jest.mock变量提升导致的引用错误 - 务必在useEffect的清理函数中解绑scroll事件,避免多个测试用例执行时残留监听器,导致测试结果互相污染
- 该方案全程没有修改或Mock
lodash.throttle的实现,完全符合要求 - Mock版本保留了原Hook的enable参数逻辑,和原实现行为保持一致,不会出现上层Hook调用异常
内容的提问来源于stack exchange,提问作者A.A
相关产品推荐
相关产品推荐

