非同期コードのテスト
JavaScriptではコードを非同期に実行することがよくあります。 非同期的に動作するコードがある場合、Jestはテスト対象のコードがいつ完了したかを別のテストに進む前に知る必要があります。 Jestはこのことを処理する方法をいくつか持っています。
Promises
テストからpromiseを返すと、Jestはそのpromiseがresolveされるまで待機します。 promiseがrejectされると、テストが失敗します。
例えば、fetchData
が'peanut butter'
という文字列でresolveされるpromiseを返すとします。 以下のようにテストすることができます:
test('the data is peanut butter', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});
Async/Await
また、async
と await
をテストで使用できます。 非同期テストを書くには、 test
に渡す関数の前にasync
キーワードを記述するだけです。 例えば、同じfetchData
シナリオは次のようにテストできます:
test('the data is peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
expect.assertions(1);
try {
await fetchData();
} catch (error) {
expect(error).toMatch('error');
}
});
async
と await
を .resolves
または .reject
と組み合わせることができます。
test('the data is peanut butter', async () => {
await expect(fetchData()).resolves.toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
await expect(fetchData()).rejects.toMatch('error');
});
これらのケースでは async
や await
は事実上、promise を使用した例と同じロジックの糖衣構文です。
promiseを返す、またはawait
するようにしましょう。return
またはawait
を省いた場合、fetchData
から返されるpromiseがresolveまたはrejectされる前に、テストが終了してしまいます。
promiseがrejectされることを期待するケースでは .catch
メソッドを使用してください。 想定した数のアサーションが呼ばれたことを確認するため、expect.assertions
を必ず追加して下さい。 Otherwise, a fulfilled promise would not fail the test.
test('the fetch fails with an error', () => {
expect.assertions(1);
return fetchData().catch(error => expect(error).toMatch('error'));
});
コールバック
promiseを使わない場合、コールバックが使えます。 例えば、fetchData
がpromiseを返すのではなく、コールバックを使うとします。つまり、データを取得し終わったら、callback(null, data)
を呼ぶとします。 返ってくるデータが'peanut butter'
という文字列であることをテストしたいとします。
デフォルトでは、Jestのテストは一度最後まで実行したら完了します。 つまり下記のテストは意図したとおりには動作しないのです。
// 実行しないでください!
test('the data is peanut butter', () => {
function callback(error, data) {
if (error) {
throw error;
}
expect(data).toBe('peanut butter');
}
fetchData(callback);
});
問題はfetchData
が完了した時点でテストも完了してしまい、コールバックが呼ばれないことです。
これを修正する別の形のtest
があります。 テストを空の引数の関数の中に記述するのではなく、 done
という1つの引数を利用します。 Jestは テストを終了する前に、done
コールバックが呼ばれるまで待ちます。
test('the data is peanut butter', done => {
function callback(error, data) {
if (error) {
done(error);
return;
}
try {
expect(data).toBe('peanut butter');
done();
} catch (error) {
done(error);
}
}
fetchData(callback);
});