You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 22:27:24