3.6 KiB
id, title, layout, category, permalink, previous, next
| id | title | layout | category | permalink | previous | next |
|---|---|---|---|---|---|---|
| tutorial-async | An Async Example | docs | Guides | docs/tutorial-async.html | tutorial-react-native | timer-mocks |
First, enable Babel support in Jest as documented in the Getting Started guide.
Let's implement a simple 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.
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.',
})
);
});
}
Now let's write a test for our async functionality. Using the resolves keyword (available in Jest 20.0.0+)
// __tests__/user-test.js
jest.mock('../request');
import * as user from '../user';
// The promise that is being tested should be returned.
it('works with promises', () => {
return expect(user.getUserName(5)).resolves.toEqual('Paul');
});
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.
async/await
Writing tests using the async/await syntax is easy. Here is
how you'd write the same example from before:
// async/await can also be used.
it('works with async/await', async () => {
await expect(user.getUserName(4)).resolves.toEqual('Mark');
});
To enable async/await in your project, install
babel-preset-env
and enable the feature in your .babelrc file.
Error handling
Errors can be handled using the keyword rejects in your expect statement. This will verify that the promise rejects and perform an assertion on the resulting error.
// Testing for async errors can be done using `catch`.
it('tests error with promises', () => {
return expect(user.getUserName(3)).rejects.toEqual({
error: 'User with 3 not found.',
});
});
// Or try-catch.
it('tests error with async/await', async () => {
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.