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

使用Jest测试结合SetTimeout和useEffect的自定义Hook失败如何解决

问题定位

    1. Redux相关依赖未正确mock
      你使用了useAppDispatch自定义Hook,但测试中没有对它进行mock,导致dispatch方法未正确初始化。同时你对profileSlice的mock逻辑错误,声明的logout mock函数和模块导出的logout没有关联,即使dispatch执行也不会触发你监听的mock函数。
    1. 时间单位不匹配
      你的Hook逻辑中写了exp * 1000,说明设计上exp是秒级Unix时间戳,但测试代码中Date.now() + 6000生成的是毫秒级时间戳,传入Hook后乘以1000会得到远大于预期的超时时间,导致定时器不会在你预期的时机触发。
    1. 伪定时器下Date.now()不匹配
      你在test用例内部才调用jest.useFakeTimers(),而exp是在describe块顶部用真实的Date.now()生成的,调用useFakeTimers()后Hook内部的Date.now()会被重置为默认值0,计算出来的timeToLogout会出现异常,甚至出现你观察到的exp为0的假象。
    1. renderHook使用方式有误
      renderHook本身已经内部处理了act包裹,不需要额外套一层act,错误的包裹可能会导致Hook的参数传递、执行时机出现异常。

修复后的测试代码

import { renderHook } from '@testing-library/react-hooks';
import useTokenExpirationCheck from './useTokenExpirationCheck';
import { logout } from '../features/profile/profileSlice';
import { useAppDispatch } from '../store/hooks';

//  mock Redux相关依赖
jest.mock('../store/hooks', () => ({
  useAppDispatch: jest.fn()
}));
const mockDispatch = jest.fn();
(useAppDispatch as jest.Mock).mockReturnValue(mockDispatch);

// 正确关联logout mock
jest.mock('../features/profile/profileSlice', () => ({
  ...jest.requireActual('../features/profile/profileSlice'),
  logout: jest.fn()
}));

describe('Expiration token', () => {
  test('should logout user', () => {
    jest.useFakeTimers();
    // 用伪定时器下的Date.now()生成秒级时间戳,6秒后过期
    const exp = Math.floor((Date.now() + 6000) / 1000);
    
    renderHook(() => useTokenExpirationCheck(exp));

    expect(logout).not.toHaveBeenCalled();
    // 快进6秒多一点,确保定时器触发
    jest.advanceTimersByTime(6001);
    
    // 验证dispatch调用了logout
    expect(mockDispatch).toHaveBeenCalledWith(logout());
    jest.useRealTimers();
  });
});

可选:Hook本身优化

建议给useEffect加清理函数,避免组件卸载/exp变更时旧定时器触发导致bug:

useEffect(() => {
  if (exp) {
    const timeToLogout = exp * 1000 - Date.now();
    const timer = setTimeout(() => {
      dispatch(logout());
    }, timeToLogout);
    // 清理定时器
    return () => clearTimeout(timer);
  }
}, [exp, dispatch]);

内容的提问来源于stack exchange,提问作者littlesvensson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 02:24:00