Jest 异步示例
首先, 像Jest 从安装开始里面所说的那样, 启用babel的支持
让我们实现一个从 API 获取用户数据并返回用户名的模块。
// user.jsimport request from './request';export function getUserName(userID) {return request('/users/' + userID).then(user => user.name);}
在上面的实现中,我们期望request.js模块返回一个 promise。我们链接一个调用来then接收用户名。
现在想象一个request.js进入网络并获取一些用户数据的实现:
// request.jsconst http = require('http');export default function request(url) {return new Promise(resolve => {// 这是一个HTTP请求的例子, 用来从API获取用户信息// This module is being mocked in __mocks__/request.jshttp.get({path: url}, response => {let data = '';response.on('data', _data => (data += _data));response.on('end', () => resolve(data));});});}
因为我们在测试中不想去网络,所以我们将request.js在__mocks__文件夹中为我们的模块创建一个手动模拟(文件夹区分大小写,__MOCKS__将不起作用)。就像是这样:
// __mocks__/request.jsconst 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.jsjest.mock('../request');import * as user from '../user';//断言必须返回一个primoseit('works with promises', () => {expect.assertions(1);return user.getUserName(4).then(data => expect(data).toEqual('Mark'));});
我们调用 jest.mock('../request ') 告诉jest 使用我们手动的创建的模拟数据。 it 断言的是将会返回一个Promise对象,你可以在任何时候给expect打电话,只要你在最后回复一个承诺。
.resolves
有一种不那么冗长的方法resolves用于将已履行的 Promise 的值与任何其他匹配器一起解包。如果 Promise 被拒绝,则断言将失败。
it('works with resolves', () => {expect.assertions(1);return expect(user.getUserName(5)).resolves.toEqual('Paul');});
async/await
也可以使用async/await语法编写测试。以下是如何编写与之前相同的示例:
// 使用async/awaitit('works with async/await', async () => {expect.assertions(1);const data = await user.getUserName(4);expect(data).toEqual('Mark');});// async/await 也可以和 `.resolves` 一起使用.it('works with async/await and resolves', async () => {expect.assertions(1);await expect(user.getUserName(5)).resolves.toEqual('Paul');});
要在项目中启用 async/await,请在你的babel.config.js文件中安装并启用@babel/preset-env功能。
错误处理
可以使用 .catch 方法处理错误。 请确保添加 expect.assertions 来验证一定数量的断言被调用。 否则一个fulfilled态的Promise 不会让测试失败︰
//用 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
该.rejects助手的工作方式类似于.resolves帮手。如果 Promise 被拒绝,则测试将自动失败。expect.assertions(number)不是必需的,但建议验证在测试期间调用了一定数量的assertions。其实不然容易忘记return/await的.resolves assertions。
// 用`.rejects`.来测试一个异步的错误it('tests error with rejects', () => {expect.assertions(1);return expect(user.getUserName(3)).rejects.toEqual({error: 'User with 3 not found.',});});// 或者与async/await 一起使用 `.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,请查看计时器模拟文档。