JSDOM 11.6.0与Sinon假定时器触发无限循环,如何规避?
解决JSDOM 11.6.0搭配Sinon假定时器触发无限循环的问题
这个坑我之前踩过,核心原因是JSDOM在初始化过程中依赖真实的定时器机制,而Sinon的useFakeTimers()会完全覆盖原生的setTimeout、setInterval等方法,导致JSDOM内部的初始化逻辑陷入无限循环。
下面给你几个实用的解决办法:
方法一:调整加载顺序(最推荐)
最简单的思路就是先完成JSDOM的加载与初始化,再启用Sinon假定时器,让JSDOM初始化时用的是真实定时器,完全避开冲突:
// 先加载并初始化JSDOM const jsdom = require('jsdom'); const dom = new jsdom.JSDOM('<!DOCTYPE html><p>Test DOM</p>'); global.window = dom.window; global.document = dom.window.document; // 之后再启用Sinon假定时器 const sinon = require('sinon'); sinon.useFakeTimers();
方法二:临时恢复真实定时器(适配必须先开假定时器的场景)
如果你的业务逻辑要求必须先启用假定时器,可以在加载JSDOM前临时恢复原生定时器,完成JSDOM初始化后再重新启用假定时器:
const sinon = require('sinon'); // 先启用假定时器并保存实例 const clock = sinon.useFakeTimers(); // 临时恢复原生定时器 clock.restore(); // 加载并初始化JSDOM const jsdom = require('jsdom'); const dom = new jsdom.JSDOM('<!DOCTYPE html><p>Test DOM</p>'); global.window = dom.window; global.document = dom.window.document; // 重新启用假定时器 sinon.useFakeTimers();
方法三:限制Sinon假定时器的覆盖范围(部分场景适用)
你可以让Sinon只覆盖你需要用到的定时器方法,避免影响JSDOM的依赖逻辑。比如只覆盖setTimeout,保留原生的setInterval(这个需要根据实际测试需求调整,不一定适配所有场景):
const sinon = require('sinon'); // 仅覆盖指定的定时器方法 sinon.useFakeTimers({ toFake: ['setTimeout'] }); // 再加载JSDOM const jsdom = require('jsdom');
额外提醒:如果测试中需要操作JSDOM环境内的定时器,建议在JSDOM初始化完成后,单独覆盖JSDOM窗口内的定时器方法,而不是一开始就覆盖全局定时器。
内容的提问来源于stack exchange,提问作者Sergio Cinos
相关产品推荐
相关产品推荐

