跳至主内容
版本:30.0

异步示例

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

首先,按照入门指南中的说明,在 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) 验证测试期间调用的断言数量(非强制要求),否则很容易忘记 returnawait .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),请参阅定时器模拟文档。