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

使用vi.spyOn()测试clearInterval时Vitest报错问题求助

问题原因及解决建议

问题原因

  1. 严格模式下的全局变量访问问题:你的组件大概率运行在严格模式中,直接调用clearInterval时,严格模式不会自动将全局变量注入当前作用域,导致代码无法找到该变量,抛出ReferenceError。
  2. Spy目标与组件上下文不匹配:测试中你用vi.spyOn(global, 'clearInterval')监控全局对象,但React组件在浏览器环境中实际访问的是window对象上的clearInterval,两者上下文不一致,导致后续清理函数调用时出现引用断层。
  3. Mock重置时机错误:你在act块中调用了vi.clearAllMocks(),该方法会重置所有mock状态,若此时组件清理函数未执行,会干扰mock的正常引用。

解决步骤

1. 修复组件中的全局变量引用

将组件中所有setInterval和clearInterval明确绑定到window对象,确保严格模式下能正确访问:

useEffect(() => {
    // Start straight away (ie before first second elapses in setInterval)
    if (distance() > 0) {
        runTimer();
    }

    const interval = window.setInterval(() => {
        if (distance() < 0) {
            // Stop Timer
            endTimer();
            window.clearInterval(interval);
        } else {
            runTimer();
        }
    }, 1000);

    return () => {
        window.clearInterval(interval);
    };
}, []);

2. 调整测试中的Spy目标

将spy目标改为window,与组件调用上下文保持一致:

test('should clear the interval when the distance is less than 0', () => {
    const date = setDate(SECOND);
    // 监控window上的clearInterval
    const clearIntervalSpy = vi.spyOn(window, 'clearInterval');

    const { unmount } = render(<CountdownClock endDate={date} etc.../>)

    act(() => {
        vi.runOnlyPendingTimers();
        vi.runOnlyPendingTimers();
    });

    // 断言定时器触发时的clearInterval调用
    expect(clearIntervalSpy).toHaveBeenCalledTimes(1);

    // 触发组件卸载,执行清理函数
    unmount();

    // 根据需求断言清理函数的调用情况
    expect(clearIntervalSpy).toHaveBeenCalledTimes(2);

    // 在测试最后重置mock
    vi.clearAllMocks();
});

3. 统一Mock重置时机

把vi.clearAllMocks()移到测试最后,或用afterEach钩子统一重置,避免干扰测试过程:

afterEach(() => {
    vi.clearAllMocks();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 13:20:49