Chai HTTP

使用 Chai 断言进行 HTTP 集成测试。
特性
- 集成测试请求组合
- 测试 HTTP 应用或外部服务
- 针对常见 HTTP 任务的断言
- chai
expect
和should
接口
安装
npm install chai-http
插件
像使用其他 Chai 插件一样使用此插件。
import chaiModule from "chai";
import chaiHttp from "chai-http";
const chai = chaiModule.use(chaiHttp);
要在网页上使用 Chai HTTP,请暂时使用最新的 v4 版本。
集成测试
Chai HTTP 通过 superagent 提供了一个用于实时集成测试的接口。为此,您必须先构建一个对应用程序或 URL 的请求。
构建后,您将获得一个可链式调用的 API,允许您指定要调用的 HTTP VERB 请求(get、post 等)。
应用程序/服务器
您可以使用函数(例如 express 或 connect 应用)或 node.js http(s) 服务器作为请求的基础。如果服务器未运行,chai-http 将找到一个合适的端口,为给定的测试进行监听。
注意:此功能仅在 Node.js 上受支持,在 Web 浏览器中不受支持。
chai.request.execute(app)
.get('/')
当将 app
传递给 request
时,它会自动打开服务器以接收传入请求(通过调用 listen()
),并且一旦发出请求,服务器将自动关闭(通过调用 .close()
)。如果您想保持服务器打开状态,也许是因为您正在发出多个请求,则必须在 .request()
之后调用 .keepOpen()
,并手动关闭服务器。
const requester = chai.request.Request(app).keepOpen()
Promise.all([
requester.get('/a'),
requester.get('/b'),
])
.then(responses => { /* ... */ })
.then(() => requester.close())
URL
您也可以使用基本 URL 作为请求的基础。
chai.request.execute('https://#:8080')
.get('/')
设置请求
一旦使用给定的 VERB(get、post 等)创建了一个请求,您就可以将这些额外的链式方法组合起来创建您的请求。
方法 | 目的 |
---|---|
.set(key, value) |
设置请求头 |
.send(data) |
设置请求数据(默认类型为 JSON) |
.type(dataType) |
更改从 .send() 方法发送的数据类型(xml、form 等) |
.attach(field, file, attachment) |
附加文件 |
.auth(username, password) |
为基本身份验证添加身份验证头 |
.query(parmasObject) |
链式调用一些 GET 参数 |
示例
.set()
// Set a request header
chai.request.execute(app)
.put('/user/me')
.set('Content-Type', 'application/json')
.send({ password: '123', confirmPassword: '123' })
.send()
// Send some JSON
chai.request.execute(app)
.put('/user/me')
.send({ password: '123', confirmPassword: '123' })
.type()
// Send some Form Data
chai.request.execute(app)
.post('/user/me')
.type('form')
.send({
'_method': 'put',
'password': '123',
'confirmPassword': '123'
})
.attach()
// Attach a file
chai.request.execute(app)
.post('/user/avatar')
.attach('imageField', fs.readFileSync('avatar.png'), 'avatar.png')
.auth()
// Authenticate with Basic authentication
chai.request.execute(app)
.get('/protected')
.auth('user', 'pass')
// Authenticate with Bearer Token
chai.request.execute(app)
.get('/protected')
.auth(accessToken, { type: 'bearer' })
.query()
// Chain some GET query parameters
chai.request.execute(app)
.get('/search')
.query({name: 'foo', limit: 10}) // /search?name=foo&limit=10
处理响应 - 传统
在以下示例中,我们使用 Chai 的 Expect 断言库
const { expect } = chai;
要发出请求并断言其响应,可以使用 end
方法
chai.request.execute(app)
.put('/user/me')
.send({ password: '123', confirmPassword: '123' })
.end((err, res) => {
expect(err).to.be.null;
expect(res).to.have.status(200);
});
注意事项
因为 end
函数传递了一个回调,所以断言是异步执行的。因此,必须使用一种机制来通知测试框架回调已完成。否则,测试将在断言被检查之前通过。
例如,在 Mocha 测试框架 中,这是通过使用 done
回调 实现的,它表示回调已完成,并且可以验证断言
it('fails, as expected', function(done) { // <= Pass in done callback
chai.request.execute('https://#:8080')
.get('/')
.end((err, res) => {
expect(res).to.have.status(123);
done(); // <= Call done to signal callback end
});
});
it('succeeds silently!', () => { // <= No done callback
chai.request.execute('https://#:8080')
.get('/')
.end((err, res) => {
expect(res).to.have.status(123); // <= Test completes before this runs
});
});
当传递 done
时,Mocha 将等待调用 done()
,或者直到 超时 过期。done
在发出完成信号时也接受一个错误参数。
处理响应 - Promise
如果 Promise
可用,request()
将变成一个支持 Promise 的库 - 并且可以链式调用 then
chai.request.execute(app)
.put('/user/me')
.send({ password: '123', confirmPassword: '123' })
.then((res) => {
expect(res).to.have.status(200);
})
.catch((err) => {
throw err;
});
在每个请求中保留 cookie
有时您需要保留来自一个请求的 cookie,并将其发送到下一个请求(例如,当您想使用第一个请求登录,然后稍后访问一个仅限身份验证的资源时)。为此,可以使用 .request.agent()
// Log in
const agent = chai.request.agent(app)
agent
.post('/session')
.send({ username: 'me', password: '123' })
.then((res) => {
expect(res).to.have.cookie('sessionid');
// The `agent` now has the sessionid cookie saved, and will send it
// back to the server in the next request:
return agent.get('/user/me')
.then((res) => {
expect(res).to.have.status(200);
});
});
注意:chai.request.agent(app)
启动的服务器在测试完成后不会自动关闭。您应该在测试后调用 agent.close()
以确保您的程序退出。
断言
Chai HTTP 模块为 expect
和 should
接口提供了许多断言。
.status (code)
- @param {Number} 状态码
断言响应具有提供的状态。
expect(res).to.have.status(200);
.header (key[, value])
- @param {String} 头部键(不区分大小写)
-
@param _{String RegExp}_ 头部值(可选)
断言一个 Response
或 Request
对象具有一个头。如果提供了一个值,则将断言等于该值。您也可以传递一个正则表达式进行检查。
注意:在 Web 浏览器中运行时,同源策略 仅允许 Chai HTTP 读取 某些头,这会导致断言失败。
expect(req).to.have.header('x-api-key');
expect(req).to.have.header('content-type', 'text/plain');
expect(req).to.have.header('content-type', /^text/);
.headers
断言一个 Response
或 Request
对象具有头。
注意:在 Web 浏览器中运行时,同源策略 仅允许 Chai HTTP 读取 某些头,这会导致断言失败。
expect(req).to.have.headers;
.ip
断言字符串代表有效的 IP 地址。
expect('127.0.0.1').to.be.an.ip;
expect('2001:0db8:85a3:0000:0000:8a2e:0370:7334').to.be.an.ip;
.json / .text / .html
断言一个 Response
或 Request
对象具有给定的内容类型。
expect(req).to.be.json;
expect(req).to.be.html;
expect(req).to.be.text;
.charset
断言一个 Response
或 Request
对象具有给定的字符集。
expect(req).to.have.charset('utf-8');
.redirect
断言一个 Response
对象具有重定向状态码。
expect(res).to.redirect;
expect(res).to.not.redirect;
.redirectTo
-
@param _{String RegExp}_ 位置 URL
断言一个 Response
对象重定向到提供的位置。
expect(res).to.redirectTo('http://example.com');
expect(res).to.redirectTo(/^\/search\/results\?orderBy=desc$/);
.param
- @param {String} 参数名
- @param {String} 参数值
断言一个 Request
对象具有一个具有给定键(可选)的查询字符串参数,等于该值
expect(req).to.have.param('orderby');
expect(req).to.have.param('orderby', 'date');
expect(req).to.not.have.param('limit');
.cookie
- @param {String} 参数名
- @param {String} 参数值
断言一个 Request
或 Response
对象具有一个具有给定键(可选)的 cookie 头,等于该值
expect(req).to.have.cookie('session_id');
expect(req).to.have.cookie('session_id', '1234');
expect(req).to.not.have.cookie('PHPSESSID');
expect(res).to.have.cookie('session_id');
expect(res).to.have.cookie('session_id', '1234');
expect(res).to.not.have.cookie('PHPSESSID');
发布
chai-http
是使用 semantic-release
发布的,并使用以下插件
commit-analyzer
从提交消息中确定下一个版本。release-notes-generator
对版本进行总结changelog
更新 CHANGELOG.md 文件。github
发布一个 GitHub 版本.git
提交版本资产。npm
发布到 npm.
许可证
(麻省理工学院许可证)
版权所有 (c) Jake Luer jake@alogicalparadox.com
特此授予任何人免费获得本软件和相关文档文件(“软件”)副本的权利,不受限制地处理软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售软件副本,以及允许获得软件的人员这样做,但须符合以下条件:
以上版权声明和本许可声明应包含在所有软件副本或实质部分中。
软件按“原样”提供,不提供任何形式的明示或暗示担保,包括但不限于适销性、特定目的适用性和不侵权的担保。在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任承担责任,无论是在合同、侵权行为或其他情况下,由软件或软件的使用或其他交易产生、引起或与之相关的。