NodeプロジェクトにJestを使用してテストカバレッジを追加する作業をしています。テストしているコードがpromise内でエラーをスローし、UnhandledPromiseRejectionWarning
メッセージが表示されますコンソールに記録されます。
テストを書いている間、これらの問題をかなり簡単に特定して解決できますが、これらの警告によって実際にJestがテストを失敗とマークすることはないため、CIはそれをキャッチしません。私は提案を探して回りましたが、あまり見つかりませんでした。
Nodeのドキュメントで、これらの警告をキャッチして処理できることがわかりました...
process.on('unhandledRejection', (error) => {
throw error; // Or whatever you like...
});
したがって、このコードをテストケースに追加するのはかなり簡単なようです。結局のところ、テスト内でError
をスローするとshouldテストが失敗します...
describe('...', () => {
it('...', () => {
process.on('uncaughtRejection', (error) => {
throw error;
});
// the rest of my test goes here
});
});
残念ながら、私が目にしている動作は、エラーがスローされますが、Jestはそれをキャッチせず、テストに失敗します。代わりに、Jestはこのエラーでクラッシュし、テストは継続して実行されません。これは望ましいことではなく、不正な動作のようです。
uncaughtRejection
ハンドラの外でエラーをスローすると、期待どおりに動作します。Jestはスローされたエラーをログに記録してテストに失敗しますが、クラッシュしません。 (つまり、テストウォッチャーはテストを監視して実行し続けます)
私がこれに取り組んだ方法は、関数の記述方法に非常に密接に関連しています。基本的に、promiseを使用する関数はすべてpromiseを返す必要があります。これにより、コードがその関数を呼び出す場合に、適切と思われる方法でエラーのキャッチを処理できます。これはmyアプローチであり、これが唯一の方法であると主張するつもりはないことに注意してください。
たとえば、この関数をテストしているとしましょう。
const myFunction = () => {
return doSomethingWithAPromise()
.then(() => {
console.log('no problems!');
return true;
});
};
テストは次のようになります。
describe('...', () => {
it('...', () => {
return myFunction()
.then((value) => {
expect(value).toBe(true);
});
});
});
それは素晴らしい作品です。約束が拒否された場合はどうなりますか?私のテストでは、拒否されたプロミスがJestに返され(私は関数呼び出しの結果を返しているため)、Jestはそれを報告できます。
代わりに、関数がpromiseを返さない場合は、次のようにする必要があります。
const myOtherFunction = () => {
doSomethingWithAPromise()
.then(() => {
console.log('no problems!');
return true;
})
.catch((err) => {
// throw the caught error here
throw err;
});
};
上記の例とは異なり、Jestにプロミスを渡さないため、Jestが拒否されたプロミスを処理する(直接的な)方法はありません。これを回避する1つの方法可能性がありますエラーをキャッチしてスローする関数にcatch
があることを確認することですが、私はそれを試していません。これ以上信頼できます。
ノードのドキュメントから site がわかりますThe process object is an instance of EventEmitter
。process
の- emit 関数を使用すると、必要に応じてuncaughtRejection
やuncaughtException
などのエラーをプログラムでトリガーできます。
it("should log the error", () => {
process.emit("unhandledRejection");
...
const loggerInfo = jest.spyOn(logger, "info");
expect(loggerInfo).toHaveBeenCalled();
});