An Async Example
Спочатку, включість Babel підтримку в Jest як зазначено в інструкції Розпочати.
Let's implement a module that fetches user data from an API and returns the user name.
// user.js
import request from './request';
export function getUserName(userID) {
return request('/users/' + userID).then(user => user.name);
}
In the above implementation, we expect the request.js
module to return a promise. We chain a call to then
to receive the user name.
Now imagine an implementation of request.js
that goes to the network and fetches some user data:
// 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));
});
});
}
Because we don't want to go to the network in our test, we are going to create a manual mock for our request.js
module in the __mocks__
folder (the folder is case-sensitive, __MOCKS__
will not work). It could look something like this:
// __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.substr('/users/'.length), 10);
process.nextTick(() =>
users[userID]
? resolve(users[userID])
: reject({
error: 'User with ' + userID + ' not found.',
}),
);
});
}
Тепер давайте напишемо тест для нашого асинхронного функціоналу.
// __tests__/user-test.js
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).toEqual('Mark'));
});
We call jest.mock('../request')
to tell Jest to use our manual mock. it
expects the return value to be a Promise that is going to be resolved. You can chain as many Promises as you like and call expect
at any time, as long as you return a Promise at the end.
.resolves
There is a less verbose way using resolves
to unwrap the value of a fulfilled promise together with any other matcher. If the promise is rejected, the assertion will fail.
it('works with resolves', () => {
expect.assertions(1);
return expect(user.getUserName(5)).resolves.toEqual('Paul');
});
async
/await
Writing tests using the async
/await
syntax is also possible. Here is how you'd write the same examples from before:
// async/await can be used.
it('works with async/await', async () => {
expect.assertions(1);
const data = await user.getUserName(4);
expect(data).toEqual('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.toEqual('Paul');
});
To enable async/await in your project, install babel-preset-env
and enable the feature in your .babelrc
file.
Обробка помилок
Errors can be handled using the .catch
method. Не забудьте додати expect.assertions
щоб переконатися, що певна кількість перевірок була виконана. Otherwise a fulfilled promise would not fail the test:
// Testing for async errors using Promise.catch.
it('tests error with promises', () => {
expect.assertions(1);
return user.getUserName(2).catch(e =>
expect(e).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 (e) {
expect(e).toEqual({
error: 'User with 1 not found.',
});
}
});
.rejects
The.rejects
helper works like the .resolves
helper. Якщо проміс буде виконано успішно, це викличе помилку в тесті. expect.assertions(number)
is not required but recommended to verify that a certain number of assertions are called during a test. It is otherwise easy to forget to return
/await
the .resolves
assertions.
// 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.',
});
});
The code for this example is available at examples/async.
If you'd like to test timers, like setTimeout
, take a look at the Timer mocks documentation.