我似乎无法在我的Jasmine测试中窥探setTimeout
和clearTimeout
,这些测试正在通过Karma运行。
我尝试了所有这些
的变体spyOn(window, 'setTimeout').and.callFake(()=>{});
spyOn(global, 'setTimeout').and.callFake(()=>{});
spyOn(window, 'clearTimeout').and.callThrough();
clock = jasmine.clock();
clock.install();
spyOn(clock, 'setTimeout').and.callThrough();
runMyCode();
expect(window.setTimeout).toHaveBeenCalled(); // no
expect(global.setTimeout).toHaveBeenCalled(); // nope
expect(window.clearTimeout).toHaveBeenCalled(); // no again
expect(clock.setTimeout).toHaveBeenCalled(); // and no
在每种情况下,我都可以确认setTimeout
已调用clearTimeout
和runMyCode
,但我总是Expected spy setTimeout to have been called.
对于window
,显然这是因为测试和跑步者(Karma窗口)处于不同的帧中(所以为什么我期望有什么不同)。但正因为如此,我无法确定是否有任何方法可以确认这些全局函数已被调用。
我知道我可以使用jasmine.clock()
来确认已经调用了超时/间隔回调,但看起来我看不到setTimeout
本身。并且确认简单地调用clearTimeout
是不可能的。
此时,我唯一能想到的是添加一个单独的抽象层来包装setTimeout
和clearTimeout
或者将函数作为依赖项注入,我以前做过,但我觉得很奇怪。
答案 0 :(得分:5)
我能够让它像这样工作:
spyOn(window, 'setTimeout');
runMyCode();
expect(setTimeout).toHaveBeenCalled();
只需从setTimeout调用中删除'window'对象。
答案 1 :(得分:3)
对于那些寻找Jest解决方案的人来说,它有专门的fake timer functions(也是可以窥探的)。
答案 2 :(得分:0)
编辑:自从提出这个问题以来,看起来Jasmine已经实现了Clock,这使得这种模拟成为可能。而且,正如Piotr Jaworski的回答所指出的那样,Facebook的基于Jasmine的Jest提供了自己的(可以说是更好的)模拟和监视定时任务的方式。
所以,答案的其余部分已经过时了......
我能找到的唯一且唯一的解决方案是使用Rewire(在我的情况下,我还需要使用Rewire-Webpack)。
Rewire确实允许您替换全局方法 - 但是一旦替换了方法,就无法监视它。因此,要实际成功使用toHaveBeenCalledWith
,您必须包装并代理模拟函数。
var rewire = require('rewire'),
myModule = rewire('./path/to/module');
describe(function () {
var mocks = {
setTimeout: function () { return 99: },
clearTimeout: function () {}
};
beforeEach(function () {
// This will work
myModule.__set__('setTimeout', function () {
mocks.setTimeout.apply(null, arguments)
})
// This will NOT work
myModule.__set__('clearTimeout', mocks.clearTimeout)
});
it('calls setTimeout', function () {
spyOn(mocks, 'setTimeout').and.callThrough();
spyOn(mocks, 'clearTimeout').and.callThrough();
myModule.doSomething(); // this will invoke setTimeout locally
expect(mocks.setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 1000);
expect(mocks.clearTimeout).toHaveBeenCalledWith(99); // Won't work (see above)
});
});
当然,这肯定会在下次Jasmine,Rewire,Karma,Webpack ......或者天气变化(grrr)时停止工作。如果这对你不起作用,请发表评论,以便将来的开发者知道。