跳至主要内容
版本:29.7

异步示例

首先,在 Jest 中启用 Babel 支持,如 入门 指南中所述。

让我们实现一个从 API 获取用户数据并返回用户名 的模块。

user.js
import request from './request';

export function getUserName(userID) {
return request(`/users/${userID}`).then(user => user.name);
}

在上面的实现中,我们期望 request.js 模块返回一个 Promise。我们链接对 then 的调用以接收用户名。

现在想象一下 request.js 的实现,它会访问网络并获取一些用户数据

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__ 文件夹中为 request.js 模块创建一个手动模拟(文件夹区分大小写,__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.`,
}),
);
});
}

现在让我们为我们的异步功能编写一个测试。

__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).toBe('Mark'));
});

我们调用 jest.mock('../request') 来告诉 Jest 使用我们的手动模拟。it 期望返回值是一个将被解析的 Promise。您可以链接任意数量的 Promise 并随时调用 expect,只要您在最后返回一个 Promise 即可。

.resolves

使用 resolves 有一种更简洁的方法,可以与任何其他匹配器一起解包已实现 Promise 的值。如果 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) 不是必需的,但建议用于验证在测试期间是否调用了特定数量的 断言。否则,很容易忘记 return/await .resolves 断言。

// 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,请查看 计时器模拟 文档。