%PDF- %PDF-
Direktori : /home/opti/workflow/node_modules/chai-http/lib/ |
Current File : /home/opti/workflow/node_modules/chai-http/lib/request.js |
/*! * 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;