Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

superagent

Package Overview
Dependencies
Maintainers
1
Versions
174
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

superagent - npm Package Compare versions

Comparing version 0.3.0 to 0.4.0

lib-cov/events.js

13

History.md
0.4.0 / 2012-03-04
==================
* Added `.head()` method [browser]. Closes #78
* Added `make test-cov` support
* Added multipart request support. Closes #11
* Added all methods that node supports. Closes #71
* Added "response" event providing a Response object. Closes #28
* Added `.query(obj)`. Closes #59
* Added `res.type` (browser). Closes #54
* Changed: default `res.body` and `res.files` to {}
* Fixed: port existing query-string fix (browser). Closes #57
0.3.0 / 2012-01-24

@@ -3,0 +16,0 @@ ==================

4

index.js
module.exports = require('./lib/node');
module.exports = process.env.SUPERAGENT_COV
? require('./lib-cov/node')
: require('./lib/node');

@@ -13,8 +13,13 @@

var Stream = require('stream').Stream
, formidable = require('formidable')
, Response = require('./response')
, parse = require('url').parse
, format = require('url').format
, methods = require('./methods')
, utils = require('./utils')
, Part = require('./part')
, mime = require('mime')
, https = require('https')
, http = require('http')
, fs = require('fs')
, qs = require('qs');

@@ -32,3 +37,3 @@

exports.version = '0.3.0';
exports.version = '0.4.0';

@@ -45,5 +50,19 @@ /**

var noop = function(){};
function noop(){};
/**
* Expose `Response`.
*/
exports.Response = Response;
/**
* Define "form" mime type.
*/
mime.define({
'application/x-www-form-urlencoded': ['form']
});
/**
* Protocol map.

@@ -70,15 +89,2 @@ */

/**
* Default MIME type map.
*
* superagent.types.xml = 'application/xml';
*
*/
exports.types = {
html: 'text/html'
, json: 'application/json'
, form: 'application/x-www-form-urlencoded'
};
/**
* Default serialization map.

@@ -100,3 +106,3 @@ *

*
* superagent.parse['application/xml'] = function(req, fn){
* superagent.parse['application/xml'] = function(res, fn){
* fn(null, result);

@@ -107,130 +113,5 @@ * };

exports.parse = {
'application/x-www-form-urlencoded': function(req, fn){
var buf = '';
req.setEncoding('ascii');
req.on('data', function(chunk){ buf += chunk; });
req.on('end', function(){
try {
fn(null, qs.parse(buf));
} catch (err) {
fn(err);
}
});
},
exports.parse = require('./parsers');
'application/json': function(req, fn){
var buf = '';
req.setEncoding('utf8');
req.on('data', function(chunk){ buf += chunk; });
req.on('end', function(){
try {
fn(null, JSON.parse(buf));
} catch (err) {
fn(err);
}
});
}
};
/**
* Initialize a new `Response` with the given `xhr`.
*
* - set flags (.ok, .error, etc)
* - parse header
*
* @param {ClientRequest} req
* @param {IncomingMessage} res
* @param {Object} options
* @api private
*/
function Response(req, res, options) {
options = options || {};
this.req = req;
this.res = res;
this.text = res.text;
this.body = res.body;
this.header = this.headers = res.headers;
this.setStatusProperties(res.statusCode);
this.setHeaderProperties(this.header);
}
/**
* Set header related properties:
*
* - `.contentType` the content type without params
*
* A response of "Content-Type: text/plain; charset=utf-8"
* will provide you with a `.contentType` of "text/plain".
*
* @param {Object} header
* @api private
*/
Response.prototype.setHeaderProperties = function(header){
// TODO: moar!
// TODO: make this a util
// content-type
var ct = this.header['content-type'] || '';
this.type = utils.type(ct);
// params
var params = utils.params(ct);
for (var key in params) this[key] = params[key];
};
/**
* Set flags such as `.ok` based on `status`.
*
* For example a 2xx response will give you a `.ok` of __true__
* whereas 5xx will be __false__ and `.error` will be __true__. The
* `.clientError` and `.serverError` are also available to be more
* specific, and `.statusType` is the class of error ranging from 1..5
* sometimes useful for mapping respond colors etc.
*
* "sugar" properties are also defined for common cases. Currently providing:
*
* - .noContent
* - .badRequest
* - .unauthorized
* - .notAcceptable
* - .notFound
*
* @param {Number} status
* @api private
*/
Response.prototype.setStatusProperties = function(status){
var type = status / 100 | 0;
// status / class
this.status = this.statusCode = status;
this.statusType = type;
// basics
this.info = 1 == type;
this.ok = 2 == type;
this.redirect = 3 == type;
this.clientError = 4 == type;
this.serverError = 5 == type;
this.error = 4 == type || 5 == type;
// sugar
this.accepted = 202 == status;
this.noContent = 204 == status;
this.badRequest = 400 == status;
this.unauthorized = 401 == status;
this.notAcceptable = 406 == status;
this.notFound = 404 == status;
};
/**
* Expose `Response`.
*/
exports.Response = Response;
/**
* Initialize a new `Request` with the given `method` and `url`.

@@ -253,4 +134,5 @@ *

this._buffer = true;
this.on('end', function(){
self.callback(new Response(self.req, self.res));
this.attachments = [];
this.on('response', function(res){
self.callback(res);
});

@@ -266,2 +148,21 @@ }

/**
* Queue the given `file` as an attachment
* with optional `filename`.
*
* @param {String} file
* @param {String} filename
* @return {Request} for chaining
* @api public
*/
Request.prototype.attach = function(file, filename){
this.attachments.push({
name: file
, part: new Part(this)
, filename: filename
});
return this;
};
/**
* Set the max redirects to `n`.

@@ -334,8 +235,6 @@ *

/**
* Set Content-Type to `type`, mapping values from `exports.types`.
* Set _Content-Type_ response header passed through `mime.lookup()`.
*
* Examples:
*
* superagent.types.xml = 'application/xml';
*
* request.post('/')

@@ -347,6 +246,11 @@ * .type('xml')

* request.post('/')
* .type('application/xml')
* .send(xmlstring)
* .type('json')
* .send(jsonstring)
* .end(callback);
*
* request.post('/')
* .type('application/json')
* .send(jsonstring)
* .end(callback);
*
* @param {String} type

@@ -358,3 +262,21 @@ * @return {Request} for chaining

Request.prototype.type = function(type){
this.set('Content-Type', exports.types[type] || type);
return this.set('Content-Type', ~type.indexOf('/')
? type
: mime.lookup(type));
};
/**
* Add `obj` to the query-string, later formatted
* in `.end()`.
*
* @param {Object} obj
* @return {Request} for chaining
* @api public
*/
Request.prototype.query = function(obj){
this._query = this._query || {};
for (var key in obj) {
this._query[key] = obj[key];
}
return this;

@@ -398,2 +320,3 @@ };

Request.prototype.send = function(data){
if ('GET' == this.method) return this.query(data);
var obj = isObject(data);

@@ -410,5 +333,8 @@

if ('GET' == this.method) return this;
if (!obj) return this;
// pre-defined type
if (this.request().getHeader('Content-Type')) return this;
// default to json
this.type('json');

@@ -442,3 +368,3 @@ return this;

this.preventBuffer();
return this.end().on('response', function(res){
return this.end().req.on('response', function(res){
res.pipe(stream, options);

@@ -492,2 +418,18 @@ });

/**
* Write the field `name` and `val`.
*
* @param {String} name
* @param {String} val
* @return {Request} for chaining
* @api public
*/
Request.prototype.field = function(name, val){
this.part()
.name(name)
.write(val);
return this;
};
/**
* Return an http[s] request.

@@ -503,3 +445,4 @@ *

, options = this.options || {}
, data = this._data || null
, data = this._data
, query = this._query
, url = this.url;

@@ -517,8 +460,12 @@

if (null == url.query) url.query = '';
// querystring
if ('GET' == this.method && null != data) {
options.path += '?' + qs.stringify(data);
data = null;
if (query) {
query = qs.stringify(query);
url.query += (url.query.length ? '&' : '') + query;
}
if (url.query.length) options.path += '?' + url.query;
// initiate request

@@ -554,5 +501,6 @@ var mod = exports.protocols[url.protocol];

var self = this
, data = this._data || null
, data = this._data
, req = this.request()
, buffer = this._buffer;
, buffer = this._buffer
, method = this.method;

@@ -563,23 +511,23 @@ // store callback

// body
if ('GET' == this.method || 'HEAD' == this.method) {
data = null;
} else if (!req._headerSent) {
// serialize stuff
var serialize = exports.serialize[req.getHeader('Content-Type')];
if (serialize) data = serialize(data);
switch (method) {
case 'GET':
case 'HEAD':
break;
default:
if (req._headerSent) break;
// serialize stuff
var serialize = exports.serialize[req.getHeader('Content-Type')];
if (serialize) data = serialize(data);
// content-length
if (null != data && !req.getHeader('Content-Length')) {
this.set('Content-Length', data.length);
}
// content-length
if (data && !req.getHeader('Content-Length')) {
this.set('Content-Length', data.length);
}
}
// multi-part boundary
if (this._boundary) {
req.write('\r\n--' + this._boundary + '--');
}
// response
req.on('response', function(res){
var max = self._maxRedirects;
var max = self._maxRedirects
, type = res.headers['content-type'] || ''
, multipart = ~type.indexOf('multipart');

@@ -591,5 +539,2 @@ // redirect

// response event
self.emit('response', res);
// zlib support

@@ -600,2 +545,22 @@ if (/^(deflate|gzip)$/.test(res.headers['content-encoding'])) {

// don't buffer multipart
if (multipart) buffer = false;
// TODO: make all parsers take callbacks
if (multipart) {
var form = new formidable.IncomingForm;
form.parse(res, function(err, fields, files){
if (err) throw err;
// TODO: handle error
// TODO: emit formidable events, parse json etc
var response = new Response(req, res);
response.body = fields;
response.files = files;
self.emit('end');
self.callback(response);
});
return;
}
// buffered response

@@ -620,5 +585,14 @@ // TODO: optional

self.res = res;
res.on('end', function(){ self.emit('end'); });
res.on('end', function(){
// TODO: unless buffering emit earlier to stream
self.emit('response', new Response(self.req, self.res));
self.emit('end');
});
});
if (this.attachments.length) return this.writeAttachments();
// multi-part boundary
if (this._boundary) this.writeFinalBoundary();
req.end(data);

@@ -629,2 +603,52 @@ return this;

/**
* Write the final boundary.
*
* @api private
*/
Request.prototype.writeFinalBoundary = function(){
this.request().write('\r\n--' + this._boundary + '--');
};
/**
* Write the attachments in sequence.
*
* @api private
*/
Request.prototype.writeAttachments = function(){
var files = this.attachments
, req = this.request()
, self = this;
function next() {
var file = files.shift();
if (!file) {
self.writeFinalBoundary();
return req.end();
}
// custom filename
if (file.filename) {
file.part.type(file.name);
file.part.set('Content-Disposition', 'attachment; filename="' + file.filename + '"');
} else {
file.part.filename(file.name);
}
var stream = fs.createReadStream(file.name);
// TODO: pipe
// TODO: handle errors
stream.on('data', function(data){
file.part.write(data);
}).on('error', function(err){
self.emit('error', err);
}).on('end', next);
}
next();
};
/**
* Expose `Request`.

@@ -664,64 +688,15 @@ */

/**
* GET `url` with optional callback `fn(err, res)`.
*
* @param {String} url
* @param {Function} fn
* @return {Request}
* @api public
*/
// generate HTTP verb methods
request.get = function(url, fn){
var req = request('GET', url);
if (fn) req.end(fn);
return req;
};
methods.forEach(function(method){
var name = 'delete' == method
? 'del'
: method;
/**
* DELETE `url` with optional callback `fn(err, res)`.
*
* @param {String} url
* @param {Function} fn
* @return {Request}
* @api public
*/
request.del = function(url, fn){
var req = request('DELETE', url);
if (fn) req.end(fn);
return req;
};
/**
* POST `url` with optional `data` and callback `fn(err, res)`.
*
* @param {String} url
* @param {Mixed} data
* @param {Function} fn
* @return {Request}
* @api public
*/
request.post = function(url, data, fn){
var req = request('POST', url);
if (data) req.send(data);
if (fn) req.end(fn);
return req;
};
/**
* PUT `url` with optional `data` and callback `fn(err, res)`.
*
* @param {String} url
* @param {Mixed} data
* @param {Function} fn
* @return {Request}
* @api public
*/
request.put = function(url, data, fn){
var req = request('PUT', url);
if (data) req.send(data);
if (fn) req.end(fn);
return req;
};
method = method.toUpperCase();
request[name] = function(url, fn){
var req = request(method, url);
fn && req.end(fn);
return req;
};
});

@@ -13,3 +13,6 @@

var utils = require('./utils')
, Stream = require('stream').Stream;
, Stream = require('stream').Stream
, mime = require('mime')
, path = require('path')
, basename = path.basename;

@@ -52,3 +55,3 @@ /**

var boundary = utils.uid(32);
this.req.set('Content-Type', 'multipart/form-data; boundary="' + boundary + '"');
this.req.set('Content-Type', 'multipart/form-data; boundary=' + boundary);
this.req._boundary = boundary;

@@ -68,3 +71,9 @@ };

if (!this._boundary) {
this.request.write('\r\n--' + this.req._boundary + '\r\n');
// TODO: formidable bug
if (!this.request._hasFirstBoundary) {
this.request.write('--' + this.req._boundary + '\r\n');
this.request._hasFirstBoundary = true;
} else {
this.request.write('\r\n--' + this.req._boundary + '\r\n');
}
this._boundary = true;

@@ -77,2 +86,47 @@ }

/**
* Set _Content-Type_ response header passed through `mime.lookup()`.
*
* Examples:
*
* res.type('html');
* res.type('.html');
*
* @param {String} type
* @return {Part}
* @api public
*/
Part.prototype.type = function(type){
return this.set('Content-Type', mime.lookup(type));
};
/**
* Set _Content-Disposition_ header field to _form-data_
* and set the _name_ param to the given string.
*
* @param {String} name
* @return {Part}
* @api public
*/
Part.prototype.name = function(name){
this.set('Content-Disposition', 'form-data; name="' + name + '"');
return this;
};
/**
* Set _Content-Disposition_ header field to _attachment_ with `filename`.
*
* @param {String} filename
* @return {Part}
* @api public
*/
Part.prototype.filename = function(filename){
this.type(filename);
this.set('Content-Disposition', 'attachment; filename="' + basename(filename) + '"');
return this;
};
/**
* Write `data` with `encoding`.

@@ -95,21 +149,11 @@ *

/**
* Return a new `Part`.
* End the part.
*
* @return {Part}
* @api public
*/
Part.prototype.part = function(){
return this.req.part();
Part.prototype.end = function(){
this.emit('end');
this.complete = true;
};
/**
* End the request.
*
* @return {Request}
* @api public
*/
Part.prototype.end = function(fn){
return this.req.end(fn);
};

@@ -207,2 +207,33 @@

/**
* Return the mime type for the given `str`.
*
* @param {String} str
* @return {String}
* @api private
*/
function type(str){
return str.split(/ *; */).shift();
};
/**
* Return header field parameters.
*
* @param {String} str
* @return {Object}
* @api private
*/
function params(str){
return str.split(/ *; */).reduce(function(obj, str){
var parts = str.split(/ *= */)
, key = parts.shift()
, val = parts.shift();
if (key && val) obj[key] = val;
return obj;
}, {});
};
/**
* Initialize a new `Response` with the given `xhr`.

@@ -266,6 +297,6 @@ *

*
* - `.contentType` the content type without params
* - `.type` the content type without params
*
* A response of "Content-Type: text/plain; charset=utf-8"
* will provide you with a `.contentType` of "text/plain".
* will provide you with a `.type` of "text/plain".
*

@@ -277,24 +308,9 @@ * @param {Object} header

Response.prototype.setHeaderProperties = function(header){
// TODO: moar!
var params = (this.header['content-type'] || '').split(/ *; */);
this.contentType = params.shift();
this.setParams(params);
};
// content-type
var ct = this.header['content-type'] || '';
this.type = type(ct);
/**
* Create properties from `params`.
*
* For example "Content-Type: text/plain; charset=utf-8"
* would provide `.charset` "utf-8".
*
* @param {Array} params
* @api private
*/
Response.prototype.setParams = function(params){
var param;
for (var i = 0, len = params.length; i < len; ++i) {
param = params[i].split(/ *= */);
this[param[0]] = param[1];
}
// params
var obj = params(ct);
for (var key in obj) this[key] = obj[key];
};

@@ -314,3 +330,3 @@

Response.prototype.parseBody = function(str){
var parse = exports.parse[this.contentType];
var parse = exports.parse[this.type];
return parse

@@ -457,2 +473,19 @@ ? parse(str)

/**
* Add `obj` to the query-string, later formatted
* in `.end()`.
*
* @param {Object} obj
* @return {Request} for chaining
* @api public
*/
Request.prototype.query = function(obj){
this._query = this._query || {};
for (var key in obj) {
this._query[key] = obj[key];
}
return this;
};
/**
* Send `data`, defaulting the `.type()` to "json" when

@@ -504,2 +537,3 @@ * an object is given.

Request.prototype.send = function(data){
if ('GET' == this.method) return this.query(data);
var obj = isObject(data);

@@ -516,3 +550,2 @@

if ('GET' == this.method) return this;
if (!obj) return this;

@@ -536,3 +569,4 @@ if (this.header['content-type']) return this;

, xhr = this.xhr = getXHR()
, data = this._data || null;
, query = this._query
, data = this._data;

@@ -548,5 +582,7 @@ // store callback

// querystring
if ('GET' == this.method && null != data) {
this.url += '?' + exports.serializeObject(data);
data = null;
if (query) {
query = exports.serializeObject(query);
this.url += ~this.url.indexOf('?')
? '&' + query
: '?' + query;
}

@@ -628,2 +664,20 @@

/**
* GET `url` with optional callback `fn(res)`.
*
* @param {String} url
* @param {Mixed} data
* @param {Function} fn
* @return {Request}
* @api public
*/
request.head = function(url, data, fn){
var req = request('HEAD', url);
if (isFunction(data)) fn = data, data = null;
if (data) req.send(data);
if (fn) req.end(fn);
return req;
};
/**
* DELETE `url` with optional callback `fn(res)`.

@@ -630,0 +684,0 @@ *

{
"name": "superagent"
, "version": "0.3.0"
, "version": "0.4.0"
, "description": "elegant progressive ajax client"
, "keywords": ["http", "ajax", "request", "agent"]
, "author": "TJ Holowaychuk <tj@vision-media.ca>"
, "dependencies": { "qs": "0.3.2" }
, "dependencies": {
"qs": "0.4.2"
, "formidable": "1.0.9"
, "mime": "1.2.5"
}
, "devDependencies": {

@@ -9,0 +13,0 @@ "express": "2.5.x"

# SuperAgent
SuperAgent is an elegant, small (~1.7kb compressed), progressive client-side HTTP request library. View the [docs](http://visionmedia.github.com/superagent/).
SuperAgent is a small progressive client-side HTTP request library, and Node.js module with the same API, sporting many high-level HTTP client features. View the [docs](http://visionmedia.github.com/superagent/).

@@ -56,3 +56,3 @@ ![super agent](http://f.cl.ly/items/3d282n3A0h0Z0K2w0q2a/Screenshot.png)

.post('/api/pet')
.data({ name: 'Manny', species: 'cat' })
.send({ name: 'Manny', species: 'cat' })
.set('X-API-Key', 'foobar')

@@ -59,0 +59,0 @@ .set('Accept', 'application/json')

@@ -382,2 +382,33 @@

/**
* Return the mime type for the given `str`.
*
* @param {String} str
* @return {String}
* @api private
*/
function type(str){
return str.split(/ *; */).shift();
};
/**
* Return header field parameters.
*
* @param {String} str
* @return {Object}
* @api private
*/
function params(str){
return str.split(/ *; */).reduce(function(obj, str){
var parts = str.split(/ *= */)
, key = parts.shift()
, val = parts.shift();
if (key && val) obj[key] = val;
return obj;
}, {});
};
/**
* Initialize a new `Response` with the given `xhr`.

@@ -441,6 +472,6 @@ *

*
* - `.contentType` the content type without params
* - `.type` the content type without params
*
* A response of "Content-Type: text/plain; charset=utf-8"
* will provide you with a `.contentType` of "text/plain".
* will provide you with a `.type` of "text/plain".
*

@@ -452,24 +483,9 @@ * @param {Object} header

Response.prototype.setHeaderProperties = function(header){
// TODO: moar!
var params = (this.header['content-type'] || '').split(/ *; */);
this.contentType = params.shift();
this.setParams(params);
};
// content-type
var ct = this.header['content-type'] || '';
this.type = type(ct);
/**
* Create properties from `params`.
*
* For example "Content-Type: text/plain; charset=utf-8"
* would provide `.charset` "utf-8".
*
* @param {Array} params
* @api private
*/
Response.prototype.setParams = function(params){
var param;
for (var i = 0, len = params.length; i < len; ++i) {
param = params[i].split(/ *= */);
this[param[0]] = param[1];
}
// params
var obj = params(ct);
for (var key in obj) this[key] = obj[key];
};

@@ -489,3 +505,3 @@

Response.prototype.parseBody = function(str){
var parse = exports.parse[this.contentType];
var parse = exports.parse[this.type];
return parse

@@ -632,2 +648,19 @@ ? parse(str)

/**
* Add `obj` to the query-string, later formatted
* in `.end()`.
*
* @param {Object} obj
* @return {Request} for chaining
* @api public
*/
Request.prototype.query = function(obj){
this._query = this._query || {};
for (var key in obj) {
this._query[key] = obj[key];
}
return this;
};
/**
* Send `data`, defaulting the `.type()` to "json" when

@@ -679,2 +712,3 @@ * an object is given.

Request.prototype.send = function(data){
if ('GET' == this.method) return this.query(data);
var obj = isObject(data);

@@ -691,3 +725,2 @@

if ('GET' == this.method) return this;
if (!obj) return this;

@@ -711,3 +744,4 @@ if (this.header['content-type']) return this;

, xhr = this.xhr = getXHR()
, data = this._data || null;
, query = this._query
, data = this._data;

@@ -723,5 +757,7 @@ // store callback

// querystring
if ('GET' == this.method && null != data) {
this.url += '?' + exports.serializeObject(data);
data = null;
if (query) {
query = exports.serializeObject(query);
this.url += ~this.url.indexOf('?')
? '&' + query
: '?' + query;
}

@@ -803,2 +839,20 @@

/**
* GET `url` with optional callback `fn(res)`.
*
* @param {String} url
* @param {Mixed} data
* @param {Function} fn
* @return {Request}
* @api public
*/
request.head = function(url, data, fn){
var req = request('HEAD', url);
if (isFunction(data)) fn = data, data = null;
if (data) req.send(data);
if (fn) req.end(fn);
return req;
};
/**
* DELETE `url` with optional callback `fn(res)`.

@@ -805,0 +859,0 @@ *

@@ -5,2 +5,2 @@ /**

* Check if `obj` is an array.
*/function isArray(obj){return"[object Array]"=={}.toString.call(obj)}function EventEmitter(){}EventEmitter.prototype.on=function(name,fn){this.$events||(this.$events={}),this.$events[name]?isArray(this.$events[name])?this.$events[name].push(fn):this.$events[name]=[this.$events[name],fn]:this.$events[name]=fn;return this},EventEmitter.prototype.addListener=EventEmitter.prototype.on,EventEmitter.prototype.once=function(name,fn){var self=this;function on(){self.removeListener(name,on),fn.apply(this,arguments)}on.listener=fn,this.on(name,on);return this},EventEmitter.prototype.removeListener=function(name,fn){if(this.$events&&this.$events[name]){var list=this.$events[name];if(isArray(list)){var pos=-1;for(var i=0,l=list.length;i<l;i++)if(list[i]===fn||list[i].listener&&list[i].listener===fn){pos=i;break}if(pos<0)return this;list.splice(pos,1),list.length||delete this.$events[name]}else(list===fn||list.listener&&list.listener===fn)&&delete this.$events[name]}return this},EventEmitter.prototype.removeAllListeners=function(name){if(name===undefined){this.$events={};return this}this.$events&&this.$events[name]&&(this.$events[name]=null);return this},EventEmitter.prototype.listeners=function(name){this.$events||(this.$events={}),this.$events[name]||(this.$events[name]=[]),isArray(this.$events[name])||(this.$events[name]=[this.$events[name]]);return this.$events[name]},EventEmitter.prototype.emit=function(name){if(!this.$events)return!1;var handler=this.$events[name];if(!handler)return!1;var args=[].slice.call(arguments,1);if("function"==typeof handler)handler.apply(this,args);else{if(!isArray(handler))return!1;var listeners=handler.slice();for(var i=0,l=listeners.length;i<l;i++)listeners[i].apply(this,args)}return!0};var superagent=function(exports){exports=request,exports.version="0.3.0";var noop=function(){};function getXHR(){if(window.XMLHttpRequest&&("file:"!=window.location.protocol||!window.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(e){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(e){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(e){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(e){}return!1}var trim="".trim?function(s){return s.trim()}:function(s){return s.replace(/(^\s*|\s*$)/g,"")};function isFunction(obj){return"function"==typeof obj}function isObject(obj){return null!=obj&&"object"==typeof obj}function serialize(obj){if(!isObject(obj))return obj;var pairs=[];for(var key in obj)pairs.push(encodeURIComponent(key)+"="+encodeURIComponent(obj[key]));return pairs.join("&")}exports.serializeObject=serialize;function parseString(str){var obj={},pairs=str.split("&"),parts,pair;for(var i=0,len=pairs.length;i<len;++i)pair=pairs[i],parts=pair.split("="),obj[decodeURIComponent(parts[0])]=decodeURIComponent(parts[1]);return obj}exports.parseString=parseString,exports.types={html:"text/html",json:"application/json",urlencoded:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},exports.serialize={"application/x-www-form-urlencoded":serialize,"application/json":JSON.stringify},exports.parse={"application/x-www-form-urlencoded":parseString,"application/json":JSON.parse};function parseHeader(str){var lines=str.split(/\r?\n/),fields={},index,line,field,val;lines.pop();for(var i=0,len=lines.length;i<len;++i)line=lines[i],index=line.indexOf(":"),field=line.slice(0,index).toLowerCase(),val=trim(line.slice(index+1)),fields[field]=val;return fields}function Response(xhr,options){options=options||{},this.xhr=xhr,this.text=xhr.responseText,this.setStatusProperties(xhr.status),this.header=parseHeader(xhr.getAllResponseHeaders()),this.setHeaderProperties(this.header),this.body=this.parseBody(this.text)}Response.prototype.setHeaderProperties=function(header){var params=(this.header["content-type"]||"").split(/ *; */);this.contentType=params.shift(),this.setParams(params)},Response.prototype.setParams=function(params){var param;for(var i=0,len=params.length;i<len;++i)param=params[i].split(/ *= */),this[param[0]]=param[1]},Response.prototype.parseBody=function(str){var parse=exports.parse[this.contentType];return parse?parse(str):null},Response.prototype.setStatusProperties=function(status){var type=status/100|0;this.status=status,this.statusType=type,this.info=1==type,this.ok=2==type,this.clientError=4==type,this.serverError=5==type,this.error=4==type||5==type,this.accepted=202==status,this.noContent=204==status||1223==status,this.badRequest=400==status,this.unauthorized=401==status,this.notAcceptable=406==status,this.notFound=404==status},exports.Response=Response;function Request(method,url){var self=this;EventEmitter.call(this),this.method=method,this.url=url,this.header={},this.set("X-Requested-With","XMLHttpRequest"),this.on("end",function(){self.callback(new Response(self.xhr))})}Request.prototype=new EventEmitter,Request.prototype.constructor=Request,Request.prototype.set=function(field,val){if(isObject(field)){for(var key in field)this.set(key,field[key]);return this}this.header[field.toLowerCase()]=val;return this},Request.prototype.type=function(type){this.set("Content-Type",exports.types[type]||type);return this},Request.prototype.send=function(data){var obj=isObject(data);if(obj&&isObject(this._data))for(var key in data)this._data[key]=data[key];else this._data=data;if("GET"==this.method)return this;if(!obj)return this;if(this.header["content-type"])return this;this.type("json");return this},Request.prototype.end=function(fn){var self=this,xhr=this.xhr=getXHR(),data=this._data||null;this.callback=fn||noop,xhr.onreadystatechange=function(){4==xhr.readyState&&self.emit("end")},"GET"==this.method&&null!=data&&(this.url+="?"+exports.serializeObject(data),data=null),xhr.open(this.method,this.url,!0);if("GET"!=this.method&&"HEAD"!=this.method){var serialize=exports.serialize[this.header["content-type"]];serialize&&(data=serialize(data))}for(var field in this.header)xhr.setRequestHeader(field,this.header[field]);xhr.send(data);return this},exports.Request=Request;function request(method,url){if("function"==typeof url)return(new Request("GET",method)).end(url);if(1==arguments.length)return new Request("GET",method);return new Request(method,url)}request.get=function(url,data,fn){var req=request("GET",url);isFunction(data)&&(fn=data,data=null),data&&req.send(data),fn&&req.end(fn);return req},request.del=function(url,fn){var req=request("DELETE",url);fn&&req.end(fn);return req},request.post=function(url,data,fn){var req=request("POST",url);data&&req.send(data),fn&&req.end(fn);return req},request.put=function(url,data,fn){var req=request("PUT",url);data&&req.send(data),fn&&req.end(fn);return req};return exports}({})
*/function isArray(obj){return"[object Array]"=={}.toString.call(obj)}function EventEmitter(){}EventEmitter.prototype.on=function(name,fn){return this.$events||(this.$events={}),this.$events[name]?isArray(this.$events[name])?this.$events[name].push(fn):this.$events[name]=[this.$events[name],fn]:this.$events[name]=fn,this},EventEmitter.prototype.addListener=EventEmitter.prototype.on,EventEmitter.prototype.once=function(name,fn){var self=this;function on(){self.removeListener(name,on),fn.apply(this,arguments)}return on.listener=fn,this.on(name,on),this},EventEmitter.prototype.removeListener=function(name,fn){if(this.$events&&this.$events[name]){var list=this.$events[name];if(isArray(list)){var pos=-1;for(var i=0,l=list.length;i<l;i++)if(list[i]===fn||list[i].listener&&list[i].listener===fn){pos=i;break}if(pos<0)return this;list.splice(pos,1),list.length||delete this.$events[name]}else(list===fn||list.listener&&list.listener===fn)&&delete this.$events[name]}return this},EventEmitter.prototype.removeAllListeners=function(name){return name===undefined?(this.$events={},this):(this.$events&&this.$events[name]&&(this.$events[name]=null),this)},EventEmitter.prototype.listeners=function(name){return this.$events||(this.$events={}),this.$events[name]||(this.$events[name]=[]),isArray(this.$events[name])||(this.$events[name]=[this.$events[name]]),this.$events[name]},EventEmitter.prototype.emit=function(name){if(!this.$events)return!1;var handler=this.$events[name];if(!handler)return!1;var args=[].slice.call(arguments,1);if("function"==typeof handler)handler.apply(this,args);else{if(!isArray(handler))return!1;var listeners=handler.slice();for(var i=0,l=listeners.length;i<l;i++)listeners[i].apply(this,args)}return!0};var superagent=function(exports){exports=request,exports.version="0.3.0";var noop=function(){};function getXHR(){if(window.XMLHttpRequest&&("file:"!=window.location.protocol||!window.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(e){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(e){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(e){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(e){}return!1}var trim="".trim?function(s){return s.trim()}:function(s){return s.replace(/(^\s*|\s*$)/g,"")};function isFunction(obj){return"function"==typeof obj}function isObject(obj){return null!=obj&&"object"==typeof obj}function serialize(obj){if(!isObject(obj))return obj;var pairs=[];for(var key in obj)pairs.push(encodeURIComponent(key)+"="+encodeURIComponent(obj[key]));return pairs.join("&")}exports.serializeObject=serialize;function parseString(str){var obj={},pairs=str.split("&"),parts,pair;for(var i=0,len=pairs.length;i<len;++i)pair=pairs[i],parts=pair.split("="),obj[decodeURIComponent(parts[0])]=decodeURIComponent(parts[1]);return obj}exports.parseString=parseString,exports.types={html:"text/html",json:"application/json",urlencoded:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},exports.serialize={"application/x-www-form-urlencoded":serialize,"application/json":JSON.stringify},exports.parse={"application/x-www-form-urlencoded":parseString,"application/json":JSON.parse};function parseHeader(str){var lines=str.split(/\r?\n/),fields={},index,line,field,val;lines.pop();for(var i=0,len=lines.length;i<len;++i)line=lines[i],index=line.indexOf(":"),field=line.slice(0,index).toLowerCase(),val=trim(line.slice(index+1)),fields[field]=val;return fields}function type(str){return str.split(/ *; */).shift()}function params(str){return str.split(/ *; */).reduce(function(obj,str){var parts=str.split(/ *= */),key=parts.shift(),val=parts.shift();return key&&val&&(obj[key]=val),obj},{})}function Response(xhr,options){options=options||{},this.xhr=xhr,this.text=xhr.responseText,this.setStatusProperties(xhr.status),this.header=parseHeader(xhr.getAllResponseHeaders()),this.setHeaderProperties(this.header),this.body=this.parseBody(this.text)}Response.prototype.setHeaderProperties=function(header){var ct=this.header["content-type"]||"";this.type=type(ct);var obj=params(ct);for(var key in obj)this[key]=obj[key]},Response.prototype.parseBody=function(str){var parse=exports.parse[this.type];return parse?parse(str):null},Response.prototype.setStatusProperties=function(status){var type=status/100|0;this.status=status,this.statusType=type,this.info=1==type,this.ok=2==type,this.clientError=4==type,this.serverError=5==type,this.error=4==type||5==type,this.accepted=202==status,this.noContent=204==status||1223==status,this.badRequest=400==status,this.unauthorized=401==status,this.notAcceptable=406==status,this.notFound=404==status},exports.Response=Response;function Request(method,url){var self=this;EventEmitter.call(this),this.method=method,this.url=url,this.header={},this.set("X-Requested-With","XMLHttpRequest"),this.on("end",function(){self.callback(new Response(self.xhr))})}Request.prototype=new EventEmitter,Request.prototype.constructor=Request,Request.prototype.set=function(field,val){if(isObject(field)){for(var key in field)this.set(key,field[key]);return this}return this.header[field.toLowerCase()]=val,this},Request.prototype.type=function(type){return this.set("Content-Type",exports.types[type]||type),this},Request.prototype.query=function(obj){this._query=this._query||{};for(var key in obj)this._query[key]=obj[key];return this},Request.prototype.send=function(data){if("GET"==this.method)return this.query(data);var obj=isObject(data);if(obj&&isObject(this._data))for(var key in data)this._data[key]=data[key];else this._data=data;return obj?this.header["content-type"]?this:(this.type("json"),this):this},Request.prototype.end=function(fn){var self=this,xhr=this.xhr=getXHR(),query=this._query,data=this._data;this.callback=fn||noop,xhr.onreadystatechange=function(){4==xhr.readyState&&self.emit("end")},query&&(query=exports.serializeObject(query),this.url+=~this.url.indexOf("?")?"&"+query:"?"+query),xhr.open(this.method,this.url,!0);if("GET"!=this.method&&"HEAD"!=this.method){var serialize=exports.serialize[this.header["content-type"]];serialize&&(data=serialize(data))}for(var field in this.header)xhr.setRequestHeader(field,this.header[field]);return xhr.send(data),this},exports.Request=Request;function request(method,url){return"function"==typeof url?(new Request("GET",method)).end(url):1==arguments.length?new Request("GET",method):new Request(method,url)}return request.get=function(url,data,fn){var req=request("GET",url);return isFunction(data)&&(fn=data,data=null),data&&req.send(data),fn&&req.end(fn),req},request.head=function(url,data,fn){var req=request("HEAD",url);return isFunction(data)&&(fn=data,data=null),data&&req.send(data),fn&&req.end(fn),req},request.del=function(url,fn){var req=request("DELETE",url);return fn&&req.end(fn),req},request.post=function(url,data,fn){var req=request("POST",url);return data&&req.send(data),fn&&req.end(fn),req},request.put=function(url,data,fn){var req=request("PUT",url);return data&&req.send(data),fn&&req.end(fn),req},exports}({});

@@ -40,4 +40,2 @@

// TODO: "response" event should be a Response
describe('request', function(){

@@ -55,2 +53,12 @@ describe('with an object', function(){

describe('with a callback', function(){
it('should invoke .end()', function(done){
request
.get('localhost:3000/login', function(res){
assert(res.status == 200);
done();
})
})
})
describe('without a schema', function(){

@@ -167,3 +175,3 @@ it('should default to http', function(done){

.end(function(res){
res.should.be.json
res.should.be.json;
done();

@@ -170,0 +178,0 @@ });

@@ -18,7 +18,2 @@

it('should expose .types', function(){
Object.keys(request.types)
.should.eql(['html', 'json', 'form']);
})
it('should expose .serialize', function(){

@@ -25,0 +20,0 @@ Object.keys(request.serialize)

@@ -19,4 +19,2 @@

// TODO: "response" event should be a Response
describe('req.send(Object) as "form"', function(){

@@ -23,0 +21,0 @@ describe('with req.type() set to form', function(){

@@ -19,4 +19,2 @@

// TODO: "response" event should be a Response
describe('req.send(Object) as "json"', function(){

@@ -23,0 +21,0 @@ it('should default to json', function(done){

@@ -8,2 +8,6 @@

function read(file) {
return fs.readFileSync(file, 'utf8');
}
app.post('/echo', function(req, res){

@@ -20,4 +24,2 @@ res.writeHead(200, req.headers);

// TODO: "response" event should be a Response
describe('Request', function(){

@@ -32,92 +34,94 @@ describe('#part()', function(){

})
})
describe('Part', function(){
describe('#pipe()', function(){
describe('with a single part', function(){
it('should construct a multipart request', function(){
var req = request.post('http://localhost:3005/echo');
it('should default res.files to {}', function(done){
var req = request.post('http://localhost:3005/echo');
req
.part()
.set('Content-Type', 'image/png')
.write('some image data');
req.end(function(res){
res.files.should.eql({});
res.body.should.eql({});
done();
});
})
req.end(function(res){
var ct = res.header['content-type'];
ct.should.include('multipart/form-data; boundary="');
describe('#field(name, value)', function(){
it('should set a multipart field value', function(done){
var req = request.post('http://localhost:3005/echo');
var body = '\r\n';
body += '--' + boundary(ct) + '\r\n';
body += 'Content-Type: image/png\r\n';
body += '\r\n';
body += 'some image data';
body += '\r\n--' + boundary(ct) + '--';
req.field('user[name]', 'tobi');
req.field('user[age]', '2');
req.field('user[species]', 'ferret');
assert(body == res.text, 'invalid multipart response');
});
req.end(function(res){
res.body['user[name]'].should.equal('tobi');
res.body['user[age]'].should.equal('2');
res.body['user[species]'].should.equal('ferret');
done();
});
})
it('should work with file attachments', function(done){
var req = request.post('http://localhost:3005/echo');
req.field('name', 'Tobi');
req.attach('test/node/fixtures/user.html', 'document');
req.field('species', 'ferret');
req.end(function(res){
res.body.name.should.equal('Tobi');
res.body.species.should.equal('ferret');
var html = res.files.document;
html.name.should.equal('document');
html.type.should.equal('text/html');
read(html.path).should.equal('<h1>name</h1>');
done();
})
})
})
describe('with several parts', function(){
it('should construct a multipart request', function(done){
describe('#attach(file)', function(){
it('should attach a file', function(done){
var req = request.post('http://localhost:3005/echo');
var req = request.post('http://localhost:3005/echo');
req.attach('test/node/fixtures/user.html');
req.attach('test/node/fixtures/user.json');
req.attach('test/node/fixtures/user.txt');
req.part()
.set('Content-Type', 'image/png')
.set('Content-Disposition', 'attachment')
.write('some image data');
req.end(function(res){
var html = res.files['user.html'];
var json = res.files['user.json'];
var text = res.files['user.txt'];
var part = req.part()
.set('Content-Type', 'text/plain');
html.name.should.equal('user.html');
html.type.should.equal('text/html');
read(html.path).should.equal('<h1>name</h1>');
part.write('foo ');
part.write('bar ');
part.write('baz');
json.name.should.equal('user.json');
json.type.should.equal('application/json');
read(json.path).should.equal('{"name":"tobi"}');
req.end(function(res){
var ct = res.header['content-type'];
ct.should.include('multipart/form-data; boundary="');
text.name.should.equal('user.txt');
text.type.should.equal('text/plain');
read(text.path).should.equal('Tobi');
var body = '';
body += '\r\n--' + boundary(ct) + '\r\n';
body += 'Content-Type: image/png\r\n';
body += 'Content-Disposition: attachment\r\n';
body += '\r\n';
body += 'some image data';
body += '\r\n--' + boundary(ct) + '\r\n';
body += 'Content-Type: text/plain\r\n';
body += '\r\n';
body += 'foo bar baz';
body += '\r\n--' + boundary(ct) + '--';
assert(body == res.text, 'invalid multipart response');
done();
});
done();
})
})
describe('with a Content-Type specified', function(){
it('should append the boundary', function(){
describe('when a file does not exist', function(){
it('should emit an error', function(done){
var req = request.post('http://localhost:3005/echo');
req
.type('multipart/form-data')
.part()
.set('Content-Type', 'image/png')
.write('some image data');
req.attach('foo');
req.attach('bar');
req.attach('baz');
req.on('error', function(err){
err.message.should.include('ENOENT, no such file');
err.path.should.equal('foo');
done();
});
req.end(function(res){
var ct = res.header['content-type'];
ct.should.include('multipart/form-data; boundary="');
var body = '\r\n';
body += '--' + boundary(ct) + '\r\n';
body += 'Content-Type: image/png\r\n';
body += '\r\n';
body += 'some image data';
body += '\r\n--' + boundary(ct) + '--';
assert(body == res.text, 'invalid multipart response');
assert(0, 'end() was called');
});

@@ -128,36 +132,127 @@ })

describe('#pipe(stream)', function(){
it('should write to the part', function(){
describe('#attach(file, filename)', function(){
it('should use the custom filename', function(done){
request
.post(':3005/echo')
.attach('test/node/fixtures/user.html', 'document')
.end(function(res){
var html = res.files.document;
html.name.should.equal('document');
html.type.should.equal('text/html');
read(html.path).should.equal('<h1>name</h1>');
done();
})
})
})
})
describe('Part', function(){
describe('with a single part', function(){
it('should construct a multipart request', function(done){
var req = request.post('http://localhost:3005/echo');
req
.part()
.set('Content-Disposition', 'attachment; name="image"; filename="image.png"')
.set('Content-Type', 'image/png')
.write('some image data');
req.end(function(res){
var ct = res.header['content-type'];
ct.should.include('multipart/form-data; boundary=');
res.body.should.eql({});
res.files.image.name.should.equal('image.png');
res.files.image.type.should.equal('image/png');
done();
});
})
})
describe('with several parts', function(){
it('should construct a multipart request', function(done){
var req = request.post('http://localhost:3005/echo');
req.part()
.set('Content-Type', 'image/png')
.set('Content-Disposition', 'attachment; filename="myimage.png"')
.write('some image data');
var part = req.part()
.set('Content-Type', 'image/png')
.set('Content-Disposition', 'attachment; filename="another.png"')
part.write('random');
part.write('thing');
part.write('here');
req.part()
.set('Content-Disposition', 'form-data; name="name"')
.set('Content-Type', 'text/plain')
.write('tobi');
req.end(function(res){
res.body.name.should.equal('tobi');
Object.keys(res.files).should.eql(['myimage.png', 'another.png']);
done();
});
})
})
describe('with a Content-Type specified', function(){
it('should append the boundary', function(done){
var req = request
.post('http://localhost:3005/echo')
.type('multipart/form-data');
req
.part()
.set('Content-Type', 'text/plain')
.set('Content-Disposition', 'form-data; name="name"')
.write('Tobi');
req.end(function(res){
res.header['content-type'].should.include('boundary=');
res.body.name.should.equal('Tobi');
done();
});
})
})
var stream = fs.createReadStream(__dirname + '/fixtures/user.html');
describe('#name(str)', function(){
it('should set Content-Disposition to form-data and name param', function(done){
var req = request
.post('http://localhost:3005/echo');
req
.part()
.name('user[name]')
.write('Tobi');
req.end(function(res){
res.body['user[name]'].should.equal('Tobi');
done();
});
})
})
var part = req.part();
part.set('Content-Type', 'text/html');
stream.pipe(part);
req.on('response', function(res){
console.log(res.statusCode);
console.log(res.text);
describe('#filename(str)', function(){
it('should set Content-Disposition and Content-Type', function(done){
var req = request
.post('http://localhost:3005/echo')
.type('multipart/form-data');
req
.part()
.filename('path/to/my.txt')
.write('Tobi');
req.end(function(res){
var file = res.files['my.txt'];
file.name.should.equal('my.txt');
file.type.should.equal('text/plain');
done();
});
// req.end(function(res){
// console.log(res.text);
// return
// var ct = res.header['content-type'];
// ct.should.include.string('multipart/form-data; boundary="');
//
// var body = '\r\n';
// body += '--' + boundary(ct) + '\r\n';
// body += 'Content-Type: image/png\r\n';
// body += '\r\n';
// body += 'some image data';
// body += '\r\n--' + boundary(ct) + '--';
//
// // assert(body == res.text, 'invalid multipart response');
// });
})
})
})

@@ -11,9 +11,11 @@

app.del('/', function(req, res){
res.send(req.query);
});
app.listen(3006);
// TODO: "response" event should be a Response
describe('req.send(Object)', function(){
describe('on a GET request', function(){
it('should send x-www-form-urlencoded data', function(done){
it('should construct the query-string', function(done){
request

@@ -29,3 +31,55 @@ .get('http://localhost:3006/')

})
it('should append to the original query-string', function(done){
request
.get('http://localhost:3006/?name=tobi')
.send({ order: 'asc' })
.end(function(res) {
res.body.should.eql({ name: 'tobi', order: 'asc' });
done();
});
});
it('should retain the original query-string', function(done){
request
.get('http://localhost:3006/?name=tobi')
.end(function(res) {
res.body.should.eql({ name: 'tobi' });
done();
});
});
})
})
})
describe('req.query(Object)', function(){
it('should construct the query-string', function(done){
request
.del('http://localhost:3006/')
.query({ name: 'tobi' })
.query({ order: 'asc' })
.query({ limit: ['1', '2'] })
.end(function(res){
res.body.should.eql({ name: 'tobi', order: 'asc', limit: ['1', '2'] });
done();
});
})
it('should append to the original query-string', function(done){
request
.del('http://localhost:3006/?name=tobi')
.query({ order: 'asc' })
.end(function(res) {
res.body.should.eql({ name: 'tobi', order: 'asc' });
done();
});
});
it('should retain the original query-string', function(done){
request
.del('http://localhost:3006/?name=tobi')
.end(function(res) {
res.body.should.eql({ name: 'tobi' });
done();
});
});
})

@@ -26,4 +26,2 @@

// TODO: "response" event should be a Response
describe('request', function(){

@@ -30,0 +28,0 @@ describe('on redirect', function(){

@@ -22,2 +22,3 @@

assert(res.ok, 'response should be ok');
assert(res.text, 'res.text');
next();

@@ -27,2 +28,11 @@ });

test('request() simple HEAD', function(next){
request.head('test.request.js').end(function(res){
assert(res instanceof request.Response, 'respond with Response');
assert(res.ok, 'response should be ok');
assert(!res.text, 'res.text');
next();
});
});
test('request() GET 5xx', function(next){

@@ -277,7 +287,7 @@ request('GET', '/error').end(function(res){

test('GET .contentType', function(next){
test('GET .type', function(next){
request
.get('/pets')
.end(function(res){
assert('application/json' == res.contentType);
assert('application/json' == res.type);
next();

@@ -344,8 +354,8 @@ });

test('GET querystring', function(next){
test('GET querystring object', function(next){
request
.get('/querystring')
.send('search=Manny&range=1..5')
.send({ search: 'Manny' })
.end(function(res){
assert.eql(res.body, { search: 'Manny', range: '1..5' });
assert.eql(res.body, { search: 'Manny' });
next();

@@ -355,8 +365,8 @@ });

test('GET querystring object', function(next){
test('GET querystring append original', function(next){
request
.get('/querystring')
.send({ search: 'Manny' })
.get('/querystring?search=Manny')
.send({ range: '1..5' })
.end(function(res){
assert.eql(res.body, { search: 'Manny' });
assert.eql(res.body, { search: 'Manny', range: '1..5' });
next();

@@ -380,3 +390,3 @@ });

request
.get('/querystring', { search: 'Manny'})
.get('/querystring', { search: 'Manny' })
.end(function(res){

@@ -383,0 +393,0 @@ assert.eql(res.body, { search: 'Manny' });

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc