使用vi.spyOn()测试clearInterval时Vitest报错问题求助
问题原因及解决建议
问题原因
- 严格模式下的全局变量访问问题:你的组件大概率运行在严格模式中,直接调用
clearInterval时,严格模式不会自动将全局变量注入当前作用域,导致代码无法找到该变量,抛出ReferenceError。 - Spy目标与组件上下文不匹配:测试中你用
vi.spyOn(global, 'clearInterval')监控全局对象,但React组件在浏览器环境中实际访问的是window对象上的clearInterval,两者上下文不一致,导致后续清理函数调用时出现引用断层。 - 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
相关产品推荐
相关产品推荐

