Reactjs 笑话:调用setTimeout的次数太多了

Reactjs 笑话:调用setTimeout的次数太多了,reactjs,unit-testing,timer,jestjs,react-hooks,Reactjs,Unit Testing,Timer,Jestjs,React Hooks,我正在测试使用setTimeout的react组件问题是,Jest表示调用了setTimeout,尽管它显然不是。有一个setTimeout用于从ui中删除某些内容,另一个用于在鼠标悬停在组件上时暂停计时器 我尝试添加一个console.log(),其中setTimeout为,并且从未调用控制台日志,这意味着没有调用应用程序中的setTimeout //应用程序 常量应用=(道具)=>{ const[show,setShow]=useState(true); const date=useRef(

我正在测试使用
setTimeout
react
组件问题是,
Jest
表示调用了
setTimeout
,尽管它显然不是。
有一个
setTimeout
用于从ui中删除某些内容,另一个用于在鼠标悬停在组件上时暂停计时器

我尝试添加一个
console.log()
,其中
setTimeout
为,并且从未调用控制台日志,这意味着没有调用应用程序中的setTimeout

//应用程序
常量应用=(道具)=>{
const[show,setShow]=useState(true);
const date=useRef(date.now());
剩余常量=useRef(道具持续时间);
让超时;
useffect(()=>{
log('shouldnotrun');
如果(道具持续时间){
超时=设置超时(()=>{
设置显示(假)
}、道具、持续时间);
}
},[道具持续时间];
常数暂停=()=>{
剩余.current-=Date.now()-Date.current;
clearTimeout(超时);
}
常量播放=()=>{
date.current=date.now();
clearTimeout(超时);
log('shouldnotrun');
超时=设置超时(()=>{
塞汀(假);
},剩余。当前);
}
返回(
{显示&&
道具内容
}
)
}
//测试
它('持续时间为false时不应设置超时',()=>{
render();
//setTimeout只调用一次,但不是来自应用程序
expect(setTimeout).toHaveBeenCalledTimes(0);
});
它('当pauseOnHover为true时应暂停计时器',()=>{
const{container}=render();
firevent.mouseOver(container.firstChild);
expect(clearTimeout).toHaveBeenCalledTimes(1);
firevent.mouseLeave(container.firstChild);
//setTimeout调用了3次,但不是来自应用程序
expect(setTimeout).toHaveBeenCalledTimes(1);
});

所以在第一个测试中,
setTimeout
不应该被调用,但我收到它被调用过一次的消息。在第二次试验中,,
setTimeout
应该被调用一次,但是被调用了3次。
这个应用程序运行得很好,我只是不理解
jest
的情况,这表明
setTimeout
被调用的次数比它被调用的次数多。

我的第一个jest测试总是调用
setTimeout
一次(没有我的组件触发它)。通过记录这个“unknown”
setTimeout
调用的参数,我发现它是通过
\u flushCallback
函数调用的,延迟为
0

查看
react test renderer
的存储库显示定义了
\u flushCallback
函数。
调度器
其中
\u flushCallback
是的一部分,它清楚地声明,当它在非DOM环境中运行时(在执行Jest测试时就是这种情况),它会使用
setTimeout


我不知道如何正确地进行这方面的研究,目前看来,调用
setTimeout
的次数测试是不可靠的。

多亏@thabemmz研究了这一问题的原因,我有了一个破解的解决方案:

函数countSetTimeoutCalls(){
return setTimeout.mock.calls.filter(([fn,t])=>(
t!==0||
!String(fn).包括(“”“flushCallback”)
));
}
用法:

//expect(设置超时)。toHaveBeenCalledTimes(2);
//变成:
期望(countSetTimeoutCalls()).toHaveLength(2);

应该非常清楚代码在做什么;它过滤掉所有看起来像来自
react test renderer
行的调用(即函数包含
\u flushCallback
,超时为0)


反应测试呈现程序的行为(甚至函数命名)的更改很脆弱,但至少现在可以做到这一点。

这里还有解决方案吗?…谢谢你;我使用了你发现的方法创建了一个(黑客攻击)解决方案,发布在下面。