Karmaで実行されているJasmineテストでは、setTimeout
とclearTimeout
をスパイできないようです。
私はこれらすべてのバリエーションを試しました
_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
をラップするために別の抽象化レイヤーを追加するか、以前に行った依存関係として関数を挿入することですが、変だと思います。
編集:この質問をしたので、Jasmineが Clock を実装したように見えます。これにより、この種のモックが可能になります。そして、Piotr Jaworskiの回答が指摘しているように、Facebookのジャスミンベースの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)。これがうまくいかない場合は、コメントを残して、将来の開発者がわかるようにしてください。
私はそれをこのように動作させることができました:
spyOn(window, 'setTimeout');
runMyCode();
expect(setTimeout).toHaveBeenCalled();
SetTimeout呼び出しから「window」オブジェクトを削除するだけです。
Jestソリューションをお探しの方のために、専用の 偽のタイマー関数 (これもスパイ可能です)があります。