异步示例
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
首先,按照入门指南中的说明,在 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__ 目录中为 request.js 创建手动模拟(注意:目录名称区分大小写,__MOCKS__ 无效)。其内容可能如下:
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 并随时使用 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),请参阅定时器模拟文档。