aboutsummaryrefslogtreecommitdiff
path: root/node_modules/chai-http/lib
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/chai-http/lib')
-rw-r--r--node_modules/chai-http/lib/http.js364
-rw-r--r--node_modules/chai-http/lib/net.js14
-rw-r--r--node_modules/chai-http/lib/request.js311
3 files changed, 689 insertions, 0 deletions
diff --git a/node_modules/chai-http/lib/http.js b/node_modules/chai-http/lib/http.js
new file mode 100644
index 0000000..4651443
--- /dev/null
+++ b/node_modules/chai-http/lib/http.js
@@ -0,0 +1,364 @@
+/*!
+ * 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) {
+ new Assertion(this._obj).to.have.property('status');
+ var status = this._obj.status;
+
+ 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]
+ , status = this._obj.status
+ , redirects = this._obj.redirects;
+
+ this.assert(
+ redirectCodes.indexOf(status) >= 0 || redirects && redirects.length
+ , "expected redirect with 30{1-3} 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} 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) {
+ this.assert(
+ redirects.indexOf(destination) > -1
+ , '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` 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');
+ * ```
+ *
+ * @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(';');
+ }
+
+ cookie = Cookie.CookieJar();
+ cookie.setCookies(header);
+ cookie = cookie.getCookie(key, new Cookie.CookieAccessInfo());
+
+ 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'
+ );
+ }
+ });
+};
diff --git a/node_modules/chai-http/lib/net.js b/node_modules/chai-http/lib/net.js
new file mode 100644
index 0000000..12fbab8
--- /dev/null
+++ b/node_modules/chai-http/lib/net.js
@@ -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;
diff --git a/node_modules/chai-http/lib/request.js b/node_modules/chai-http/lib/request.js
new file mode 100644
index 0000000..fa583de
--- /dev/null
+++ b/node_modules/chai-http/lib/request.js
@@ -0,0 +1,311 @@
+/*!
+ * 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')
+ * .field('_method', 'put')
+ * .field('password', '123')
+ * .field('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 promise library, such as
+ * [es6-promise](https://github.com/jakearchibald/es6-promise) or
+ * [kriskowal/q](https://github.com/kriskowal/q) and call the `addPromise`
+ * method to use that library with Chai HTTP. For example:
+ *
+ * ```js
+ * var chai = require('chai');
+ * chai.use(require('chai-http'));
+ *
+ * // Add promise support if this does not exist natively.
+ * if (!global.Promise) {
+ * var q = require('q');
+ * chai.request.addPromises(q.Promise);
+ * }
+ * ```
+ *
+ * #### 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 = {};
+
+ methods.forEach(function (method) {
+ obj[method] = function (path) {
+ return new Test(server, method, path);
+ };
+ });
+ 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);
+}
+util.inherits(Test, Request);
+
+function serverAddress (app, path) {
+ if ('string' === typeof app) {
+ return app + path;
+ }
+ var addr = app.address();
+ if (!addr) {
+ app.listen(0);
+ addr = app.address();
+ }
+ 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;
+}
+util.inherits(TestAgent, Agent || Request);
+
+// 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;