マイセットアップがchai
、sinon
、chai-sinon
、chai-as-promised
、babel
とES6構文を使用しています。モカチャイSinonテストアクセスできない約束/非同期/イベント・エミッタ
私は、次の(減少)コード
// example.js
'use strict';
import EventEmitter from 'events';
class Dispatcher extends EventEmitter {
send(x) {
doSomethingAsync() // promise is NOT returned
.then(() => {
this.emit('sent');
})
.catch((err) => {
this.emit('error', err);
});
}
}
注持っている:doSomethingAsyncからの約束が返されていませんが。
は、ここで私は私がsend
の結果としてdoSomethingAsync
からの約束を返すことができれば、これを行う方法を知っている私の(縮小)テストファイル
let dispatcher;
let onSent;
let onError;
beforeEach(() => {
dispatcher = new Dispatcher();
onSent = sinon.stub();
onError= sinon.stub();
dispatcher.on('sent', onSent);
dispatcher.on('error', onError);
});
describe('send',() => {
it('should emit "error" on sendFn error instead of "sent"',() => {
... set up state for failure ...
dispatcher.send(...);
... What do I do here or how do I wrap the following? ...
expect(onSent).not.to.have.been.called;
expect(onError).to.have.been.called;
});
});
だが、それはそうではないのです(そしてできなくなります決して)ここに。私が持っているのは、「送信済み」または「エラー」イベントのいずれかが最終的に放出されるという知識です。
私の理想的な構文は次のようになります。
expect(onError).to.eventually.have
しかし、それは動作しません。私はexpect
を新しい約束事で包むだけで、エラーのないバージョンを次のように動作させることができます。しかし、私はこれがなぜ機能するのか分かりません。
// This one works for some unknown reason!
it('should emit "send" on send success',() => {
... set up state for success ...
dispatcher.send(...);
return Promise.resolve().then(() => {
expect(onSent).to.have.been.called;
expect(onError).not.to.have.been.called;
});
});
内側の約束を公開するような方法でコードをリファクタリングすることができれば、これは解決するのが簡単です。私は他の状況で何度も何度もやっています。しかし、私の質問はここにあります非常に具体的にこれを解決する方法正確なパターン;すなわち、私が約束を暴くためにコードをリファクタリングできないときに、特にアクセス不能な約束または非同期コードの副作用をテストする方法。
私が試してみましたが、少なくともテストは
- 約束に期待を包む期待を呼び出す前に、私はそのすべてのインナーコールバック/約束を完了するために必要な送信機能をトリガすることができるかどうかを確認するだけで、次の 両方の種々の非同期/待つパターンでコールと期待を送信ラップタイムアウト
- に期待をラップ
sinon.useFakeTimers
- を用い
- 制御時間
ありがとうございます。
EDIT:
[OK]を、ので、これは完全にばかげているが、ここでは両方の解決と約束を拒否するために機能するソリューションがあります:
it('should behave as expected already!', (done) => {
... set up for failure or success as desired
dispatcher.send();
process.nextTick(() => {
Promise.resolve().then(() => {
... expectations ...
done();
});
});
});
Iが原因(と私は、これがうまくいくと思います私は、スローされたエラーや拒否された約束が現在のティックで直ちに処理され、解決された約束は次のティックで待ち行列に入れられると仮定します。したがって... process.nextTick
は、次のティックでこの関数をキューに入れ、すべてのキャッチ/エラーを完了させ、Promise.resolveによって、キューに入れられた約束が実行された後にキューに入れられるようにします。ちなみに、orderまたはnextTickとpromise.resolve()も切り替えることができ、うまく動作します。
NBイベントは、(本当に非同期に放出されている場合など、独自のprocess.nextTick
その後、あなたは3レベルの巣を持っている必要があります。どちらの約束-nextTick-約束またはnextTick-約束-nextTick。
私の言葉でそれは厄介である
...まだタイムアウトよりも良いけれども:!テストは、あなたが約束を拒否/解決するためにテストしているコードのブロックを待っていないので、D