This commit is contained in:
Lev
2021-06-16 19:39:43 -05:00
parent 2dc386e7fd
commit 51ce0e142a
2210 changed files with 263077 additions and 0 deletions

View File

@ -0,0 +1,94 @@
### Note
As of 2.0.0, the History.md file has been deprecated. [Please refer to the full
commit logs available on GitHub](https://github.com/chaijs/chai-http/commits/master).
---
1.0.0 / 2014-10-08
==================
* update readme
* Merge pull request #14 from keithamus/fix-master
* Fix #13: Convert unroutable addresses to localhost
* Fix #13: Add proper detection of Promise capabilities in tests
* Merge pull request #12 from keithamus/patch-1
* add travis badge
* add travis support
* Fix typo
* Merge pull request #11 from keithamus/refactor-agent
* (chore) Regenerate README.md
* Add list of contributors to package.json
* Add simple usage docs for request api
* Fix typo in readme
* Add cookie assertions
* Add URL query string parameter assertions
* Add request.agent() which allows persisting of cookies
* Add Promises support
* Listen on random port in tests - not 4000 which may be taken
* Add Test class to exports, to enable extending
* Drastically simplify chai.request() by inheriting superagent
* Update SuperAgent to v0.19.x
* Drop harbor and pauli deps.
0.5.0 / 2014-08-19
==================
* Merge pull request #9 from hurrymaplelad/assert_redirect
* Add redirect assertions
* Merge pull request #8 from lxanders/improveReadme
* Fixed missing word and improved wording in documentation
0.4.0 / 2013-06-25
==================
* support: [readme] cleanup
* Merge pull request #7 from pezra/newer-superagent
* remove previous additions to the history
* bump superagent version dependency
* Merge pull request #5 from wookiehangover/patch-1
* Fixing typo in Readme
* readme typo
0.3.0 / 2012-10-24
==================
* minor tweak to http docs
* Readme auto generation support
* readme preview
* improve readme code comments
* add readme
* documentation for request api
* update http assertion docs
* add request test for existing url
* support and tests for header existence
* improve type detection error message
* add support for superagent based testing
* code cleanup
* convert to tdd
* clean up test runner
0.2.0 / 2012-05-15
==================
* chai 1.0.0 compatibility
* update package.json
0.1.0 / 2012-03-10
==================
* Merge branch 'refs/heads/dev'
* git/npm ignore
* Add `Asssertion#ip`.
* Docs.
* Add test for Assertion#headers.
* Add test for Assertion#json, Assertion#html Assertion#text.
* Add test for Assertion#header.
* Add test for Assertion#status.
0.0.1 / 2012-03-06
==================
* prepping for release 0.0.1
* first lib commit
* initial commit

View File

@ -0,0 +1,398 @@
# Chai HTTP [![Build Status](https://travis-ci.org/chaijs/chai-http.svg?branch=master)](https://travis-ci.org/chaijs/chai-http)
> HTTP integration testing with Chai assertions.
#### Features
- integration test request composition
- test http apps or external services
- assertions for common http tasks
- chai `expect` and `should` interfaces
#### Installation
This is a addon plugin for the [Chai Assertion Library](http://chaijs.com). Install via [npm](http://npmjs.org).
npm install chai-http
#### Plugin
Use this plugin as you would all other Chai plugins.
```js
var chai = require('chai')
, chaiHttp = require('chai-http');
chai.use(chaiHttp);
```
To use Chai HTTP on a web page, just include the [`dist/chai-http.js`](dist/chai-http.js) file:
```html
<script src="chai.js"></script>
<script src="chai-http.js"></script>
<script>
chai.use(chaiHttp);
</script>
```
## Integration Testing
Chai HTTP provides an interface for live integration
testing via [superagent](https://github.com/visionmedia/superagent).
To do this, you must first
construct a request to an application or url.
Upon construction you are provided a chainable api that
allows you to specify the http VERB request (get, post, etc)
that you wish to invoke.
#### Application / Server
You may use a function (such as an express or connect app)
or a node.js http(s) server as the foundation for your request.
If the server is not running, chai-http will find a suitable
port to listen on for a given test.
__Note:__ This feature is only supported on Node.js, not in web browsers.
```js
chai.request(app)
.get('/')
```
When passing an `app` to `request`; it will automatically open the server for
incoming requests (by calling `listen()`) and, once a request has been made
the server will automatically shut down (by calling `.close()`). If you want to
keep the server open, perhaps if you're making multiple requests, you must call
`.keepOpen()` after `.request()`, and manually close the server down:
```js
var requester = chai.request(app).keepOpen()
Promise.all([
requester.get('/a'),
requester.get('/b'),
])
.then(responses => ....)
.then(() => requester.close())
```
#### URL
You may also use a base url as the foundation of your request.
```js
chai.request('http://localhost:8080')
.get('/')
```
#### Setting up requests
Once a request is created with a given VERB, it can have headers, form data,
json, or even file attachments added to it, all with a simple API:
```js
// Send some JSON
chai.request(app)
.put('/user/me')
.set('X-API-Key', 'foobar')
.send({ password: '123', confirmPassword: '123' })
```
```js
// Send some Form Data
chai.request(app)
.post('/user/me')
.type('form')
.send({
'_method': 'put',
'password': '123',
'confirmPassword': '123'
})
```
```js
// Attach a file
chai.request(app)
.post('/user/avatar')
.attach('imageField', fs.readFileSync('avatar.png'), 'avatar.png')
```
```js
// Authenticate with Basic authentication
chai.request(app)
.get('/protected')
.auth('user', 'pass')
```
```js
// Chain some GET query parameters
chai.request(app)
.get('/search')
.query({name: 'foo', limit: 10}) // /search?name=foo&limit=10
```
#### Dealing with the response - traditional
In the following examples we use Chai's Expect assertion library:
```js
var expect = chai.expect;
```
To make the request and assert on its response, the `end` method can be used:
```js
chai.request(app)
.put('/user/me')
.send({ password: '123', confirmPassword: '123' })
.end(function (err, res) {
expect(err).to.be.null;
expect(res).to.have.status(200);
});
```
##### Caveat
Because the `end` function is passed a callback, assertions are run
asynchronously. Therefore, a mechanism must be used to notify the testing
framework that the callback has completed. Otherwise, the test will pass before
the assertions are checked.
For example, in the [Mocha test framework](http://mochajs.org/), this is
accomplished using the
[`done` callback](https://mochajs.org/#asynchronous-code), which signal that the
callback has completed, and the assertions can be verified:
```js
it('fails, as expected', function(done) { // <= Pass in done callback
chai.request('http://localhost:8080')
.get('/')
.end(function(err, res) {
expect(res).to.have.status(123);
done(); // <= Call done to signal callback end
});
});
it('succeeds silently!', function() { // <= No done callback
chai.request('http://localhost:8080')
.get('/')
.end(function(err, res) {
expect(res).to.have.status(123); // <= Test completes before this runs
});
});
```
When `done` is passed in, Mocha will wait until the call to `done()`, or until
the [timeout](http://mochajs.org/#timeouts) expires. `done` also accepts an
error parameter when signaling completion.
#### Dealing with the response - Promises
If `Promise` is available, `request()` becomes a Promise capable library -
and chaining of `then`s becomes possible:
```js
chai.request(app)
.put('/user/me')
.send({ password: '123', confirmPassword: '123' })
.then(function (res) {
expect(res).to.have.status(200);
})
.catch(function (err) {
throw err;
});
```
__Note:__ Node.js version 0.10.x and some older web browsers do not have
native promise support. You can use any spec compliant library, such as:
- [kriskowal/q](https://github.com/kriskowal/q)
- [stefanpenner/es6-promise](https://github.com/stefanpenner/es6-promise)
- [petkaantonov/bluebird](https://github.com/petkaantonov/bluebird)
- [then/promise](https://github.com/then/promise)
You will need to set the library you use to `global.Promise`, before
requiring in chai-http. For example:
```js
// Add promise support if this does not exist natively.
if (!global.Promise) {
global.Promise = require('q');
}
var chai = require('chai');
chai.use(require('chai-http'));
```
#### Retaining cookies with each request
Sometimes you need to keep cookies from one request, and send them with the
next (for example, when you want to login with the first request, then access an authenticated-only resource later). For this, `.request.agent()` is available:
```js
// Log in
var agent = chai.request.agent(app)
agent
.post('/session')
.send({ username: 'me', password: '123' })
.then(function (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(function (res) {
expect(res).to.have.status(200);
});
});
```
Note: The server started by `chai.request.agent(app)` will not automatically close following the test(s). You should call `agent.close()` after your tests to ensure your program exits.
## Assertions
The Chai HTTP module provides a number of assertions
for the `expect` and `should` interfaces.
### .status (code)
* **@param** _{Number}_ status number
Assert that a response has a supplied status.
```js
expect(res).to.have.status(200);
```
### .header (key[, value])
* **@param** _{String}_ header key (case insensitive)
* **@param** _{String|RegExp}_ header value (optional)
Assert that a `Response` or `Request` object has a header.
If a value is provided, equality to value will be asserted.
You may also pass a regular expression to check.
__Note:__ When running in a web browser, the
[same-origin policy](https://tools.ietf.org/html/rfc6454#section-3)
only allows Chai HTTP to read
[certain headers](https://www.w3.org/TR/cors/#simple-response-header),
which can cause assertions to fail.
```js
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
Assert that a `Response` or `Request` object has headers.
__Note:__ When running in a web browser, the
[same-origin policy](https://tools.ietf.org/html/rfc6454#section-3)
only allows Chai HTTP to read
[certain headers](https://www.w3.org/TR/cors/#simple-response-header),
which can cause assertions to fail.
```js
expect(req).to.have.headers;
```
### .ip
Assert that a string represents valid ip address.
```js
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
Assert that a `Response` or `Request` object has a given content-type.
```js
expect(req).to.be.json;
expect(req).to.be.html;
expect(req).to.be.text;
```
### .redirect
Assert that a `Response` object has a redirect status code.
```js
expect(res).to.redirect;
expect(res).to.not.redirect;
```
### .redirectTo
* **@param** _{String|RegExp}_ location url
Assert that a `Response` object redirects to the supplied location.
```js
expect(res).to.redirectTo('http://example.com');
expect(res).to.redirectTo(/^\/search\/results\?orderBy=desc$/);
```
### .param
* **@param** _{String}_ parameter name
* **@param** _{String}_ parameter value
Assert that a `Request` object has a query string parameter with a given
key, (optionally) equal to value
```js
expect(req).to.have.param('orderby');
expect(req).to.have.param('orderby', 'date');
expect(req).to.not.have.param('limit');
```
### .cookie
* **@param** _{String}_ parameter name
* **@param** _{String}_ parameter value
Assert that a `Request` or `Response` object has a cookie header with a
given key, (optionally) equal to value
```js
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');
```
## License
(The MIT License)
Copyright (c) Jake Luer <jake@alogicalparadox.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
module.exports = require('./lib/http');

View File

@ -0,0 +1,388 @@
/*!
* chai-http
* Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
* MIT Licensed
*/
/**
* ## Assertions
*
* The Chai HTTP module provides a number of assertions
* for the `expect` and `should` interfaces.
*/
module.exports = function (chai, _) {
/*!
* Module dependencies.
*/
var net = require('net');
var qs = require('qs');
var url = require('url');
var Cookie = require('cookiejar');
/*!
* Aliases.
*/
var Assertion = chai.Assertion
, i = _.inspect;
/*!
* Expose request builder
*/
chai.request = require('./request');
/*!
* Content types hash. Used to
* define `Assertion` properties.
*
* @type {Object}
*/
var contentTypes = {
json: 'application/json'
, text: 'text/plain'
, html: 'text/html'
};
/*!
* Return a header from `Request` or `Response` object.
*
* @param {Request|Response} object
* @param {String} Header
* @returns {String|Undefined}
*/
function getHeader(obj, key) {
if (key) key = key.toLowerCase();
if (obj.getHeader) return obj.getHeader(key);
if (obj.headers) return obj.headers[key];
};
/**
* ### .status (code)
*
* Assert that a response has a supplied status.
*
* ```js
* expect(res).to.have.status(200);
* ```
*
* @param {Number} status number
* @name status
* @api public
*/
Assertion.addMethod('status', function (code) {
var hasStatus = Boolean('status' in this._obj || 'statusCode' in this._obj);
new Assertion(hasStatus).assert(
hasStatus
, "expected #{act} to have keys 'status', or 'statusCode'"
, null // never negated
, hasStatus // expected
, this._obj // actual
, false // no diff
);
var status = this._obj.status || this._obj.statusCode;
this.assert(
status == code
, 'expected #{this} to have status code #{exp} but got #{act}'
, 'expected #{this} to not have status code #{act}'
, code
, status
);
});
/**
* ### .header (key[, value])
*
* Assert that a `Response` or `Request` object has a header.
* If a value is provided, equality to value will be asserted.
* You may also pass a regular expression to check.
*
* __Note:__ When running in a web browser, the
* [same-origin policy](https://tools.ietf.org/html/rfc6454#section-3)
* only allows Chai HTTP to read
* [certain headers](https://www.w3.org/TR/cors/#simple-response-header),
* which can cause assertions to fail.
*
* ```js
* 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/);
* ```
*
* @param {String} header key (case insensitive)
* @param {String|RegExp} header value (optional)
* @name header
* @api public
*/
Assertion.addMethod('header', function (key, value) {
var header = getHeader(this._obj, key);
if (arguments.length < 2) {
this.assert(
'undefined' !== typeof header || null === header
, 'expected header \'' + key + '\' to exist'
, 'expected header \'' + key + '\' to not exist'
);
} else if (arguments[1] instanceof RegExp) {
this.assert(
value.test(header)
, 'expected header \'' + key + '\' to match ' + value + ' but got ' + i(header)
, 'expected header \'' + key + '\' not to match ' + value + ' but got ' + i(header)
, value
, header
);
} else {
this.assert(
header == value
, 'expected header \'' + key + '\' to have value ' + value + ' but got ' + i(header)
, 'expected header \'' + key + '\' to not have value ' + value
, value
, header
);
}
});
/**
* ### .headers
*
* Assert that a `Response` or `Request` object has headers.
*
* __Note:__ When running in a web browser, the
* [same-origin policy](https://tools.ietf.org/html/rfc6454#section-3)
* only allows Chai HTTP to read
* [certain headers](https://www.w3.org/TR/cors/#simple-response-header),
* which can cause assertions to fail.
*
* ```js
* expect(req).to.have.headers;
* ```
*
* @name headers
* @api public
*/
Assertion.addProperty('headers', function () {
this.assert(
this._obj.headers || this._obj.getHeader
, 'expected #{this} to have headers or getHeader method'
, 'expected #{this} to not have headers or getHeader method'
);
});
/**
* ### .ip
*
* Assert that a string represents valid ip address.
*
* ```js
* expect('127.0.0.1').to.be.an.ip;
* expect('2001:0db8:85a3:0000:0000:8a2e:0370:7334').to.be.an.ip;
* ```
*
* @name ip
* @api public
*/
Assertion.addProperty('ip', function () {
this.assert(
net.isIP(this._obj)
, 'expected #{this} to be an ip'
, 'expected #{this} to not be an ip'
);
});
/**
* ### .json / .text / .html
*
* Assert that a `Response` or `Request` object has a given content-type.
*
* ```js
* expect(req).to.be.json;
* expect(req).to.be.html;
* expect(req).to.be.text;
* ```
*
* @name json
* @name html
* @name text
* @api public
*/
function checkContentType (name) {
var val = contentTypes[name];
Assertion.addProperty(name, function () {
new Assertion(this._obj).to.have.headers;
var ct = getHeader(this._obj, 'content-type')
, ins = i(ct) === 'undefined'
? 'headers'
: i(ct);
this.assert(
ct && ~ct.indexOf(val)
, 'expected ' + ins + ' to include \'' + val + '\''
, 'expected ' + ins + ' to not include \'' + val + '\''
);
});
}
Object
.keys(contentTypes)
.forEach(checkContentType);
/**
* ### .redirect
*
* Assert that a `Response` object has a redirect status code.
*
* ```js
* expect(res).to.redirect;
* ```
*
* @name redirect
* @api public
*/
Assertion.addProperty('redirect', function() {
var redirectCodes = [301, 302, 303, 307, 308]
, status = this._obj.status
, redirects = this._obj.redirects;
this.assert(
redirectCodes.indexOf(status) >= 0 || redirects && redirects.length
, "expected redirect with 30X status code but got " + status
, "expected not to redirect but got " + status + " status"
);
});
/**
* ### .redirectTo
*
* Assert that a `Response` object redirects to the supplied location.
*
* ```js
* expect(res).to.redirectTo('http://example.com');
* ```
*
* @param {String|RegExp} location url
* @name redirectTo
* @api public
*/
Assertion.addMethod('redirectTo', function(destination) {
var redirects = this._obj.redirects;
new Assertion(this._obj).to.redirect;
if(redirects && redirects.length) {
var hasRedirected;
if (Object.prototype.toString.call(destination) === '[object RegExp]') {
hasRedirected = redirects.some(redirect => destination.test(redirect));
} else {
hasRedirected = redirects.indexOf(destination) > -1;
}
this.assert(
hasRedirected
, 'expected redirect to ' + destination + ' but got ' + redirects.join(' then ')
, 'expected not to redirect to ' + destination + ' but got ' + redirects.join(' then ')
);
} else {
var assertion = new Assertion(this._obj);
_.transferFlags(this, assertion);
assertion.with.header('location', destination);
}
});
/**
* ### .param
*
* Assert that a `Request` object has a query string parameter with a given
* key, (optionally) equal to value
*
* ```js
* expect(req).to.have.param('orderby');
* expect(req).to.have.param('orderby', 'date');
* expect(req).to.not.have.param('limit');
* ```
*
* @param {String} parameter name
* @param {String} parameter value
* @name param
* @api public
*/
Assertion.addMethod('param', function(name, value) {
var assertion = new Assertion();
_.transferFlags(this, assertion);
assertion._obj = qs.parse(url.parse(this._obj.url).query);
assertion.property.apply(assertion, arguments);
});
/**
* ### .cookie
*
* Assert that a `Request`, `Response` or `Agent` object has a cookie header with a
* given key, (optionally) equal to value
*
* ```js
* 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');
* expect(agent).to.have.cookie('session_id');
* expect(agent).to.have.cookie('session_id', '1234');
* expect(agent).to.not.have.cookie('PHPSESSID');
* ```
*
* @param {String} parameter name
* @param {String} parameter value
* @name param
* @api public
*/
Assertion.addMethod('cookie', function (key, value) {
var header = getHeader(this._obj, 'set-cookie')
, cookie;
if (!header) {
header = (getHeader(this._obj, 'cookie') || '').split(';');
}
if (this._obj instanceof chai.request.agent && this._obj.jar) {
cookie = this._obj.jar.getCookie(key, Cookie.CookieAccessInfo.All);
} else {
cookie = Cookie.CookieJar();
cookie.setCookies(header);
cookie = cookie.getCookie(key, Cookie.CookieAccessInfo.All);
}
if (arguments.length === 2) {
this.assert(
cookie.value == value
, 'expected cookie \'' + key + '\' to have value #{exp} but got #{act}'
, 'expected cookie \'' + key + '\' to not have value #{exp}'
, value
, cookie.value
);
} else {
this.assert(
'undefined' !== typeof cookie || null === cookie
, 'expected cookie \'' + key + '\' to exist'
, 'expected cookie \'' + key + '\' to not exist'
);
}
});
};

View File

@ -0,0 +1,14 @@
/*!
* chai-http - request helper
* Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
* MIT Licensed
*/
/*!
* net.isIP shim for browsers
*/
var isIP = require('is-ip');
exports.isIP = isIP;
exports.isIPv4 = isIP.v4;
exports.isIPv6 = isIP.v6;

View File

@ -0,0 +1,353 @@
/*!
* chai-http - request helper
* Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
* MIT Licensed
*/
/*!
* Module dependancies
*/
var http = require('http')
, https = require('https')
, methods = require('methods')
, superagent = require('superagent')
, Agent = superagent.agent
, Request = superagent.Request
, util = require('util');
/**
* ## Integration Testing
*
* Chai HTTP provides an interface for live integration
* testing via [superagent](https://github.com/visionmedia/superagent).
* To do this, you must first
* construct a request to an application or url.
*
* Upon construction you are provided a chainable api that
* allows you to specify the http VERB request (get, post, etc)
* that you wish to invoke.
*
* #### Application / Server
*
* You may use a function (such as an express or connect app)
* or a node.js http(s) server as the foundation for your request.
* If the server is not running, chai-http will find a suitable
* port to listen on for a given test.
*
* __Note:__ This feature is only supported on Node.js, not in web browsers.
*
* ```js
* chai.request(app)
* .get('/')
* ```
*
* #### URL
*
* You may also use a base url as the foundation of your request.
*
* ```js
* chai.request('http://localhost:8080')
* .get('/')
* ```
*
* #### Setting up requests
*
* Once a request is created with a given VERB, it can have headers, form data,
* json, or even file attachments added to it, all with a simple API:
*
* ```js
* // Send some JSON
* chai.request(app)
* .put('/user/me')
* .set('X-API-Key', 'foobar')
* .send({ password: '123', confirmPassword: '123' })
* ```
*
* ```js
* // Send some Form Data
* chai.request(app)
* .post('/user/me')
* .type('form')
* .send({'_method': 'put'})
* .send({'password': '123'})
* .send({'confirmPassword', '123'})
* ```
*
* ```js
* // Attach a file
* chai.request(app)
* .post('/user/avatar')
* .attach('imageField', fs.readFileSync('avatar.png'), 'avatar.png')
* ```
*
* ```js
* // Authenticate with Basic authentication
* chai.request(app)
* .get('/protected')
* .auth('user', 'pass')
* ```
*
* ```js
* // Chain some GET query parameters
* chai.request(app)
* .get('/search')
* .query({name: 'foo', limit: 10}) // /search?name=foo&limit=10
* ```
*
* #### Dealing with the response - traditional
*
* To make the request and assert on its response, the `end` method can be used:
*
* ```js
* chai.request(app)
* .put('/user/me')
* .send({ password: '123', confirmPassword: '123' })
* .end(function (err, res) {
* expect(err).to.be.null;
* expect(res).to.have.status(200);
* });
* ```
* ##### Caveat
* Because the `end` function is passed a callback, assertions are run
* asynchronously. Therefore, a mechanism must be used to notify the testing
* framework that the callback has completed. Otherwise, the test will pass before
* the assertions are checked.
*
* For example, in the [Mocha test framework](http://mochajs.org/), this is
* accomplished using the
* [`done` callback](https://mochajs.org/#asynchronous-code), which signal that the
* callback has completed, and the assertions can be verified:
*
* ```js
* it('fails, as expected', function(done) { // <= Pass in done callback
* chai.request('http://localhost:8080')
* .get('/')
* .end(function(err, res) {
* expect(res).to.have.status(123);
* done(); // <= Call done to signal callback end
* });
* }) ;
*
* it('succeeds silently!', function() { // <= No done callback
* chai.request('http://localhost:8080')
* .get('/')
* .end(function(err, res) {
* expect(res).to.have.status(123); // <= Test completes before this runs
* });
* }) ;
* ```
*
* When `done` is passed in, Mocha will wait until the call to `done()`, or until
* the [timeout](http://mochajs.org/#timeouts) expires. `done` also accepts an
* error parameter when signaling completion.
*
* #### Dealing with the response - Promises
*
* If `Promise` is available, `request()` becomes a Promise capable library -
* and chaining of `then`s becomes possible:
*
* ```js
* chai.request(app)
* .put('/user/me')
* .send({ password: '123', confirmPassword: '123' })
* .then(function (res) {
* expect(res).to.have.status(200);
* })
* .catch(function (err) {
* throw err;
* })
* ```
*
* __Note:__ Node.js version 0.10.x and some older web browsers do not have
* native promise support. You can use any spec compliant library, such as:
* - [kriskowal/q](https://github.com/kriskowal/q)
* - [stefanpenner/es6-promise](https://github.com/stefanpenner/es6-promise)
* - [petkaantonov/bluebird](https://github.com/petkaantonov/bluebird)
* - [then/promise](https://github.com/then/promise)
* You will need to set the library you use to `global.Promise`, before
* requiring in chai-http. For example:
*
* ```js
* // Add promise support if this does not exist natively.
* if (!global.Promise) {
* global.Promise = require('q');
* }
* var chai = require('chai');
* chai.use(require('chai-http'));
*
* ```
*
* #### Retaining cookies with each request
*
* Sometimes you need to keep cookies from one request, and send them with the
* next. For this, `.request.agent()` is available:
*
* ```js
* // Log in
* var agent = chai.request.agent(app)
* agent
* .post('/session')
* .send({ username: 'me', password: '123' })
* .then(function (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(function (res) {
* expect(res).to.have.status(200);
* })
* })
* ```
*
*/
module.exports = function (app) {
/*!
* @param {Mixed} function or server
* @returns {Object} API
*/
var server = ('function' === typeof app)
? http.createServer(app)
: app
, obj = {};
var keepOpen = false
if (typeof server !== 'string' && server && server.listen && server.address) {
if (!server.address()) {
server = server.listen(0)
}
}
obj.keepOpen = function() {
keepOpen = true
return this
}
obj.close = function(callback) {
if (server && server.close) {
server.close(callback);
}
else if(callback) {
callback();
}
return this
}
methods.forEach(function (method) {
obj[method] = function (path) {
return new Test(server, method, path)
.on('end', function() {
if(keepOpen === false) {
obj.close();
}
});
};
});
obj.del = obj.delete;
return obj;
};
module.exports.Test = Test;
module.exports.Request = Test;
module.exports.agent = TestAgent;
/*!
* Test
*
* An extension of superagent.Request,
* this provides the same chainable api
* as superagent so all things can be modified.
*
* @param {Object|String} server, app, or url
* @param {String} method
* @param {String} path
* @api private
*/
function Test (app, method, path) {
Request.call(this, method, path);
this.app = app;
this.url = typeof app === 'string' ? app + path : serverAddress(app, path);
this.ok(function() {
return true;
});
}
util.inherits(Test, Request);
function serverAddress (app, path) {
if ('string' === typeof app) {
return app + path;
}
var addr = app.address();
if (!addr) {
throw new Error('Server is not listening')
}
var protocol = (app instanceof https.Server) ? 'https' : 'http';
// If address is "unroutable" IPv4/6 address, then set to localhost
if (addr.address === '0.0.0.0' || addr.address === '::') {
addr.address = '127.0.0.1';
}
return protocol + '://' + addr.address + ':' + addr.port + path;
}
/*!
* agent
*
* Follows the same API as superagent.Request,
* but allows persisting of cookies between requests.
*
* @param {Object|String} server, app, or url
* @param {String} method
* @param {String} path
* @api private
*/
function TestAgent(app) {
if (!(this instanceof TestAgent)) return new TestAgent(app);
if (typeof app === 'function') app = http.createServer(app);
(Agent || Request).call(this);
this.app = app;
if (typeof app !== 'string' && app && app.listen && app.address && !app.address()) {
this.app = app.listen(0)
}
}
util.inherits(TestAgent, Agent || Request);
TestAgent.prototype.close = function close(callback) {
if (this.app && this.app.close) {
this.app.close(callback)
}
return this
}
TestAgent.prototype.keepOpen = function keepOpen() {
return this
}
// override HTTP verb methods
methods.forEach(function(method){
TestAgent.prototype[method] = function(url){
var req = new Test(this.app, method, url)
, self = this;
if (Agent) {
// When running in Node, cookies are managed via
// `Agent._saveCookies()` and `Agent._attachCookies()`.
req.on('response', function (res) { self._saveCookies(res); });
req.on('redirect', function (res) { self._saveCookies(res); });
req.on('redirect', function () { self._attachCookies(req); });
this._attachCookies(req);
}
else {
// When running in a web browser, cookies are managed via `Request.withCredentials()`.
// The browser will attach cookies based on same-origin policy.
// https://tools.ietf.org/html/rfc6454#section-3
req.withCredentials();
}
return req;
};
});
TestAgent.prototype.del = TestAgent.prototype.delete;

View File

@ -0,0 +1,119 @@
{
"_from": "chai-http",
"_id": "chai-http@4.3.0",
"_inBundle": false,
"_integrity": "sha512-zFTxlN7HLMv+7+SPXZdkd5wUlK+KxH6Q7bIEMiEx0FK3zuuMqL7cwICAQ0V1+yYRozBburYuxN1qZstgHpFZQg==",
"_location": "/chai-http",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "chai-http",
"name": "chai-http",
"escapedName": "chai-http",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/chai-http/-/chai-http-4.3.0.tgz",
"_shasum": "3c37c675c1f4fe685185a307e345de7599337c1a",
"_spec": "chai-http",
"_where": "C:\\Files\\Repositories\\UoL\\CM2010 Software Design and Development\\Topic 4\\8.3.1",
"author": {
"name": "Jake Luer",
"email": "jake@alogicalparadox.com"
},
"browser": {
"http": false,
"https": false,
"net": "./lib/net.js",
"querystring": "qs"
},
"bugs": {
"url": "https://github.com/chaijs/chai-http/issues"
},
"bundleDependencies": false,
"contributors": [
{
"name": "Jake Luer",
"email": "jake@alogicalparadox.com"
},
{
"name": "Veselin Todorov",
"email": "hi@vesln.com"
},
{
"name": "Keith Cirkel",
"email": "oss@keithcirkel.co.uk",
"url": "http://keithcirkel.co.uk"
}
],
"dependencies": {
"@types/chai": "4",
"@types/superagent": "^3.8.3",
"cookiejar": "^2.1.1",
"is-ip": "^2.0.0",
"methods": "^1.1.2",
"qs": "^6.5.1",
"superagent": "^3.7.0"
},
"deprecated": false,
"description": "Extend Chai Assertion library with tests for http apis",
"devDependencies": {
"chai": "4",
"coveralls": "^3.0.0",
"dox": "^0.9.0",
"es6-shim": "^0.35.1",
"http-server": "^0.10.0",
"istanbul": "^0.4.3",
"mocha": "^4.0.1",
"npm-run-all": "^4.1.1",
"simplifyify": "^4.0.0",
"typescript": "^3.0.1"
},
"engines": {
"node": ">=4"
},
"files": [
"dist/chai-http.js",
"lib/*.js",
"index.js",
"types/index.d.ts"
],
"homepage": "https://github.com/chaijs/chai-http#readme",
"keywords": [
"chai",
"chai-plugin",
"browser",
"http",
"request",
"vendor",
"supertest",
"superagent"
],
"license": "MIT",
"main": "./index",
"name": "chai-http",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/chaijs/chai-http.git"
},
"scripts": {
"build": "npm run build:readme && npm run build:js && npm run build:ts",
"build:js": "simplifyify lib/http.js --outfile dist/chai-http.js --bundle --minify --debug --standalone chaiHttp",
"build:readme": "rm -rf README.md && node ./support/readme",
"build:ts": "cd types && tsc",
"posttest": "if [ -z \"$COVERALLS_REPO_TOKEN\" ]; then cat coverage/lcov.info | coveralls; fi",
"prebuild:js": "rm -rf dist",
"server": "http-server -o -c-1",
"start": "npm-run-all --parallel watch server",
"test": "istanbul cover --report lcovonly _mocha",
"watch": "npm run build:js -- --watch"
},
"types": "./types/index.d.ts",
"version": "4.3.0"
}

View File

@ -0,0 +1,61 @@
// Definitions by: Wim Looman <https://github.com/Nemo157>
// Liam Jones <https://github.com/G1itcher>
// Federico Caselli <https://github.com/CaselIT>
// Bas Luksenburg <https://github.com/bas-l>
// Austin Cawley-Edwards <https://github.com/austince>
// TypeScript Version: 3.0
/// <reference types="chai" />
import * as request from 'superagent';
// Merge namespace with global chai
declare global {
namespace Chai {
interface ChaiStatic {
request: ChaiHttpRequest;
}
interface ChaiHttpRequest {
(server: any): ChaiHttp.Agent;
agent(server: any): ChaiHttp.Agent;
addPromises(promiseConstructor: PromiseConstructorLike): void;
}
interface Assertion {
redirectTo(location: string|RegExp): Assertion;
param(key: string, value?: string): Assertion;
cookie(key: string, value?: string): Assertion;
status(code: number): Assertion;
statusCode(code: number): Assertion;
header(key: string, value?: string | RegExp): Assertion;
headers: Assertion;
json: Assertion;
text: Assertion;
html: Assertion;
redirect: Assertion;
}
interface TypeComparison {
ip: Assertion;
}
}
namespace ChaiHttp {
interface Response extends request.Response {}
interface Agent extends request.SuperAgentStatic {
keepOpen(): Agent;
close(callback?: (err: any) => void): Agent;
}
}
}
declare function chaiHttp(chai: any, utils: any): void;
export = chaiHttp;