非同期処理の例
まず、はじめにガイドに記載されているように、JestでBabelのサポートを有効にします。
APIからユーザーデータを取得してユーザー名を返すモジュールを実装してみましょう。
import request from './request';
export function getUserName(userID) {
return request(`/users/${userID}`).then(user => user.name);
}
上記の実装では、request.js
モジュールがPromiseを返すことを期待しています。 then
を呼び出してユーザー名を受け取ります。
ネットワークにアクセスしてユーザーデータを取得するrequest.js
の実装を考えてみましょう。
const http = require('http');
export default function request(url) {
return new Promise(resolve => {
// This is an example of an http request, for example to fetch
// user data from an API.
// This module is being mocked in __mocks__/request.js
http.get({path: url}, response => {
let data = '';
response.on('data', _data => (data += _data));
response.on('end', () => resolve(data));
});
});
}
テストでネットワークにアクセスしたくないため、__mocks__
フォルダ(フォルダは大文字と小文字が区別されるため、__MOCKS__
は機能しません)にrequest.js
モジュールの手動モックを作成します。次のようなものになります。
const users = {
4: {name: 'Mark'},
5: {name: 'Paul'},
};
export default function request(url) {
return new Promise((resolve, reject) => {
const userID = parseInt(url.slice('/users/'.length), 10);
process.nextTick(() =>
users[userID]
? resolve(users[userID])
: reject({
error: `User with ${userID} not found.`,
}),
);
});
}
それでは、非同期機能のテストを作成しましょう。
jest.mock('../request');
import * as user from '../user';
// The assertion for a promise must be returned.
it('works with promises', () => {
expect.assertions(1);
return user.getUserName(4).then(data => expect(data).toBe('Mark'));
});
jest.mock('../request')
を呼び出して、Jestに手動モックを使用するように指示します。 it
は、解決されるPromiseが返されることを期待します。最後にPromiseを返す限り、好きなだけPromiseをチェーンしていつでもexpect
を呼び出すことができます。
.resolves
resolves
を使用すると、冗長性を減らし、他のマッチャーと一緒に履行されたPromiseの値をunwrapできます。Promiseが拒否された場合、アサーションは失敗します。
it('works with resolves', () => {
expect.assertions(1);
return expect(user.getUserName(5)).resolves.toBe('Paul');
});
async
/await
async
/await
構文を使用してテストを作成することもできます。以前と同じ例を記述する方法は次のとおりです。
// async/await can be used.
it('works with async/await', async () => {
expect.assertions(1);
const data = await user.getUserName(4);
expect(data).toBe('Mark');
});
// async/await can also be used with `.resolves`.
it('works with async/await and resolves', async () => {
expect.assertions(1);
await expect(user.getUserName(5)).resolves.toBe('Paul');
});
プロジェクトでasync/awaitを有効にするには、@babel/preset-env
をインストールし、babel.config.js
ファイルでこの機能を有効にします。
エラー処理
エラーは.catch
メソッドを使用して処理できます。必ずexpect.assertions
を追加して、特定の数のアサーションが呼び出されていることを確認してください。そうでないと、履行されたPromiseはテストに失敗しません。
// Testing for async errors using Promise.catch.
it('tests error with promises', () => {
expect.assertions(1);
return user.getUserName(2).catch(error =>
expect(error).toEqual({
error: 'User with 2 not found.',
}),
);
});
// Or using async/await.
it('tests error with async/await', async () => {
expect.assertions(1);
try {
await user.getUserName(1);
} catch (error) {
expect(error).toEqual({
error: 'User with 1 not found.',
});
}
});
.rejects
.rejects
ヘルパーは、.resolves
ヘルパーと同様に機能します。Promiseが履行された場合、テストは自動的に失敗します。 expect.assertions(number)
は必須ではありませんが、テスト中に特定の数のアサーションが呼び出されることを確認するために推奨されます。そうでなければ、.resolves
アサーションをreturn
/await
することを忘れがちです。
// Testing for async errors using `.rejects`.
it('tests error with rejects', () => {
expect.assertions(1);
return expect(user.getUserName(3)).rejects.toEqual({
error: 'User with 3 not found.',
});
});
// Or using async/await with `.rejects`.
it('tests error with async/await and rejects', async () => {
expect.assertions(1);
await expect(user.getUserName(3)).rejects.toEqual({
error: 'User with 3 not found.',
});
});
この例のコードは、examples/asyncにあります。
setTimeout
などのタイマーをテストする場合は、タイマーモックのドキュメントを参照してください。