unexpected-http
Advanced tools
Comparing version 6.1.0 to 6.1.1
/*global window, setTimeout, clearTimeout, Uint8Array*/ | ||
var http = require('http'), | ||
https = require('https'), | ||
messy = require('messy'), | ||
_ = require('underscore'); | ||
var http = require('http'); | ||
var https = require('https'); | ||
var messy = require('messy'); | ||
var _ = require('underscore'); | ||
module.exports = { | ||
name: 'unexpected-http', | ||
installInto: function (expect) { | ||
expect | ||
.child() | ||
.use(require('unexpected-messy')) | ||
.exportAssertion([ | ||
'<string|object> to yield [HTTP] response <any>', | ||
'<string|object> to yield [HTTP] response satisfying <any>' | ||
], function (expect, subject, value) { | ||
var that = this; | ||
var context = {}, | ||
expectedResponseError; | ||
if (Object.prototype.toString.call(value) === '[object Error]' || value instanceof Error) { | ||
expectedResponseError = value; | ||
} else if (value && typeof value === 'object' && (typeof Buffer === 'undefined' || !Buffer.isBuffer(value))) { | ||
value = _.extend({}, value); | ||
if (value.error) { | ||
expectedResponseError = value.error; | ||
} | ||
} | ||
name: 'unexpected-http', | ||
installInto: function(expect) { | ||
expect | ||
.child() | ||
.use(require('unexpected-messy')) | ||
.exportAssertion( | ||
[ | ||
'<string|object> to yield [HTTP] response <any>', | ||
'<string|object> to yield [HTTP] response satisfying <any>' | ||
], | ||
function(expect, subject, value) { | ||
var context = {}; | ||
var expectedResponseError; | ||
if ( | ||
Object.prototype.toString.call(value) === '[object Error]' || | ||
value instanceof Error | ||
) { | ||
expectedResponseError = value; | ||
} else if ( | ||
value && | ||
typeof value === 'object' && | ||
(typeof Buffer === 'undefined' || !Buffer.isBuffer(value)) | ||
) { | ||
value = _.extend({}, value); | ||
if (value.error) { | ||
expectedResponseError = value.error; | ||
} | ||
} | ||
var request; | ||
return expect.promise(function (resolve, reject) { | ||
var requestOptions = {}; | ||
var requestTimeout = subject.timeout || 0; | ||
var requestBody = subject.body; | ||
var requestBodyIsJson = false; | ||
var requestBodyIsStream = false; | ||
var request; | ||
return expect | ||
.promise(function(resolve, reject) { | ||
var requestOptions = {}; | ||
var requestTimeout = subject.timeout || 0; | ||
var requestBody = subject.body; | ||
var requestBodyIsJson = false; | ||
var requestBodyIsStream = false; | ||
if (Array.isArray(requestBody) || (requestBody && typeof requestBody === 'object' && (typeof Buffer === 'undefined' || !Buffer.isBuffer(requestBody)))) { | ||
if (typeof requestBody.pipe === 'function') { | ||
subject = _.omit(subject, 'body'); | ||
requestBodyIsStream = true; | ||
} else { | ||
requestBodyIsJson = true; | ||
} | ||
} | ||
if ( | ||
Array.isArray(requestBody) || | ||
(requestBody && | ||
typeof requestBody === 'object' && | ||
(typeof Buffer === 'undefined' || | ||
!Buffer.isBuffer(requestBody))) | ||
) { | ||
if (typeof requestBody.pipe === 'function') { | ||
subject = _.omit(subject, 'body'); | ||
requestBodyIsStream = true; | ||
} else { | ||
requestBodyIsJson = true; | ||
} | ||
} | ||
if (!subject.isMessyHttpRequest) { | ||
subject = new messy.HttpRequest(subject && typeof subject === 'object' ? _.omit(subject, 'timeout') : subject); | ||
} | ||
if (!subject.isMessyHttpRequest) { | ||
subject = new messy.HttpRequest( | ||
subject && typeof subject === 'object' | ||
? _.omit(subject, 'timeout') | ||
: subject | ||
); | ||
} | ||
var httpRequest = context.httpRequest = subject; | ||
httpRequest.protocol = httpRequest.protocol || 'HTTP/1.1'; | ||
if (requestBodyIsJson) { | ||
if (!httpRequest.headers.has('Content-Type')) { | ||
httpRequest.headers.set('Content-Type', 'application/json'); | ||
} | ||
httpRequest.body = JSON.stringify(httpRequest.body); | ||
} | ||
// Avoid using Transfer-Encoding: chunked for the request body as that confuses NGINX -- and we know the length | ||
// of the request body: | ||
if (!requestBodyIsStream && !httpRequest.headers.has('Content-Length')) { | ||
var contentLength = 0; | ||
if (httpRequest.unchunkedBody) { | ||
contentLength = httpRequest.unchunkedBody.length; | ||
} | ||
httpRequest.headers.set('Content-Length', contentLength); | ||
} | ||
var httpRequest = (context.httpRequest = subject); | ||
httpRequest.protocol = httpRequest.protocol || 'HTTP/1.1'; | ||
if (requestBodyIsJson) { | ||
if (!httpRequest.headers.has('Content-Type')) { | ||
httpRequest.headers.set('Content-Type', 'application/json'); | ||
} | ||
httpRequest.body = JSON.stringify(httpRequest.body); | ||
} | ||
// Avoid using Transfer-Encoding: chunked for the request body as that confuses NGINX -- and we know the length | ||
// of the request body: | ||
if ( | ||
!requestBodyIsStream && | ||
!httpRequest.headers.has('Content-Length') | ||
) { | ||
var contentLength = 0; | ||
if (httpRequest.unchunkedBody) { | ||
contentLength = httpRequest.unchunkedBody.length; | ||
} | ||
httpRequest.headers.set('Content-Length', contentLength); | ||
} | ||
var headers = httpRequest.headers.toCanonicalObject(); | ||
Object.keys(headers).forEach(function (headerName) { | ||
headers[headerName] = headers[headerName].join(', '); | ||
}); | ||
_.extend(requestOptions, { | ||
host: httpRequest.host || (typeof window === 'object' && typeof window.location !== 'undefined' ? window.location.hostname : 'localhost'), | ||
port: httpRequest.port || (typeof window === 'object' && (typeof window.location !== 'undefined' ? window.location.port : window.location.protocol === 'https:' ? 443 : 80)) || (httpRequest.encrypted ? 443 : 80), | ||
method: httpRequest.method, | ||
path: httpRequest.path + (httpRequest.search || ''), | ||
headers: headers, | ||
mode: 'disable-fetch' | ||
}, _.pick(subject, ['ca', 'cert', 'key', 'rejectUnauthorized'])); | ||
var headers = httpRequest.headers.toCanonicalObject(); | ||
Object.keys(headers).forEach(function(headerName) { | ||
headers[headerName] = headers[headerName].join(', '); | ||
}); | ||
_.extend( | ||
requestOptions, | ||
{ | ||
host: | ||
httpRequest.host || | ||
(typeof window === 'object' && | ||
typeof window.location !== 'undefined' | ||
? window.location.hostname | ||
: 'localhost'), | ||
port: | ||
httpRequest.port || | ||
(typeof window === 'object' && | ||
(typeof window.location !== 'undefined' | ||
? window.location.port | ||
: window.location.protocol === 'https:' | ||
? 443 | ||
: 80)) || | ||
(httpRequest.encrypted ? 443 : 80), | ||
method: httpRequest.method, | ||
path: httpRequest.path + (httpRequest.search || ''), | ||
headers: headers, | ||
mode: 'disable-fetch' | ||
}, | ||
_.pick(subject, ['ca', 'cert', 'key', 'rejectUnauthorized']) | ||
); | ||
// set the protocol and scheme for HTTPS requests in the browser | ||
if (typeof window === 'object' && httpRequest.encrypted) { | ||
_.extend(requestOptions, { | ||
scheme: 'https', | ||
protocol: 'https:' | ||
}); | ||
} | ||
// set the protocol and scheme for HTTPS requests in the browser | ||
if (typeof window === 'object' && httpRequest.encrypted) { | ||
_.extend(requestOptions, { | ||
scheme: 'https', | ||
protocol: 'https:' | ||
}); | ||
} | ||
var timeout = null; | ||
if (requestTimeout > 0) { | ||
timeout = setTimeout(function () { | ||
that.errorMode = 'nested'; | ||
try { | ||
expect.fail('expected a response within {0} ms', requestTimeout); | ||
} catch (err) { | ||
reject(err); | ||
} | ||
}, requestTimeout); | ||
} | ||
request = (httpRequest.encrypted ? https : http).request(requestOptions).on('response', function (response) { | ||
var chunks = []; | ||
response.on('data', function (chunk) { | ||
chunks.push(chunk); | ||
}).on('end', function () { | ||
if (timeout) { | ||
clearTimeout(timeout); | ||
} | ||
var timeout = null; | ||
if (requestTimeout > 0) { | ||
timeout = setTimeout(function() { | ||
expect.errorMode = 'nested'; | ||
try { | ||
expect.fail( | ||
'expected a response within {0} ms', | ||
requestTimeout | ||
); | ||
} catch (err) { | ||
reject(err); | ||
} | ||
}, requestTimeout); | ||
} | ||
request = (httpRequest.encrypted ? https : http) | ||
.request(requestOptions) | ||
.on('response', function(response) { | ||
var chunks = []; | ||
response | ||
.on('data', function(chunk) { | ||
chunks.push(chunk); | ||
}) | ||
.on('end', function() { | ||
if (timeout) { | ||
clearTimeout(timeout); | ||
} | ||
var body; | ||
if (chunks.length > 0 && typeof Buffer !== 'undefined' && Buffer.isBuffer(chunks[0])) { | ||
body = Buffer.concat(chunks); | ||
} else if (chunks.length > 0 && chunks[0] instanceof Uint8Array) { | ||
// Browserify: Make sure we end up with a Buffer instance: | ||
if (chunks.length === 1) { | ||
body = new Buffer(chunks[0]); | ||
} else { | ||
var totalLength = 0; | ||
var i; | ||
for (i = 0 ; i < chunks.length ; i += 1) { | ||
totalLength += chunks[i].length; | ||
} | ||
body = new Buffer(totalLength); | ||
var offset = 0; | ||
for (i = 0 ; i < chunks.length ; i += 1) { | ||
for (var j = 0 ; j < chunks[i].length ; j += 1) { | ||
body[offset] = chunks[i][j]; | ||
offset += 1; | ||
} | ||
} | ||
} | ||
} else { | ||
// String or no chunks | ||
body = chunks.join(''); | ||
var body; | ||
if ( | ||
chunks.length > 0 && | ||
typeof Buffer !== 'undefined' && | ||
Buffer.isBuffer(chunks[0]) | ||
) { | ||
body = Buffer.concat(chunks); | ||
} else if ( | ||
chunks.length > 0 && | ||
chunks[0] instanceof Uint8Array | ||
) { | ||
// Browserify: Make sure we end up with a Buffer instance: | ||
if (chunks.length === 1) { | ||
body = new Buffer(chunks[0]); | ||
} else { | ||
var totalLength = 0; | ||
var i; | ||
for (i = 0; i < chunks.length; i += 1) { | ||
totalLength += chunks[i].length; | ||
} | ||
body = new Buffer(totalLength); | ||
var offset = 0; | ||
for (i = 0; i < chunks.length; i += 1) { | ||
for (var j = 0; j < chunks[i].length; j += 1) { | ||
body[offset] = chunks[i][j]; | ||
offset += 1; | ||
} | ||
var httpResponse = context.httpResponse = new messy.HttpResponse({ | ||
statusCode: response.statusCode, | ||
statusMessage: http.STATUS_CODES[response.statusCode], | ||
protocol: 'HTTP/' + (response.httpVersionMajor || '1') + '.' + (response.httpVersionMinor || '1'), | ||
headers: response.headers, | ||
unchunkedBody: body | ||
}); | ||
resolve(context.httpExchange = new messy.HttpExchange({ | ||
request: httpRequest, | ||
response: httpResponse | ||
})); | ||
}).on('error', reject); | ||
}).on('error', reject); | ||
} | ||
} | ||
} else { | ||
// String or no chunks | ||
body = chunks.join(''); | ||
} | ||
var httpResponse = (context.httpResponse = new messy.HttpResponse( | ||
{ | ||
statusCode: response.statusCode, | ||
statusMessage: http.STATUS_CODES[response.statusCode], | ||
protocol: | ||
'HTTP/' + | ||
(response.httpVersionMajor || '1') + | ||
'.' + | ||
(response.httpVersionMinor || '1'), | ||
headers: response.headers, | ||
unchunkedBody: body | ||
} | ||
)); | ||
resolve( | ||
(context.httpExchange = new messy.HttpExchange({ | ||
request: httpRequest, | ||
response: httpResponse | ||
})) | ||
); | ||
}) | ||
.on('error', reject); | ||
}) | ||
.on('error', reject); | ||
if (request.xhr) { | ||
// In browserify: Make sure the response comes back as a Uint8Array | ||
request.xhr.responseType = 'arraybuffer'; | ||
} | ||
if (request.xhr) { | ||
// In browserify: Make sure the response comes back as a Uint8Array | ||
request.xhr.responseType = 'arraybuffer'; | ||
} | ||
if (requestBodyIsStream) { | ||
requestBody.pipe(request); | ||
requestBody.on('error', reject); | ||
} else { | ||
request.end(httpRequest.unchunkedBody); | ||
} | ||
}).then(function (httpExchange) { | ||
expect(expectedResponseError, 'to be undefined'); | ||
return expect(httpExchange, 'to satisfy', { response: value }); | ||
}, function (err) { | ||
if (request) { | ||
request.abort(); | ||
} | ||
if (expectedResponseError) { | ||
expect(err, 'to equal', expectedResponseError); | ||
} else if (err.code) { | ||
// Socket or DNS error | ||
expect.fail({ | ||
diff: function (output) { | ||
output.error(err.message); | ||
return output; | ||
}, | ||
code: err.code | ||
}); | ||
} else { | ||
throw err; | ||
} | ||
}).then(function () { | ||
return context; | ||
}); | ||
if (requestBodyIsStream) { | ||
requestBody.pipe(request); | ||
requestBody.on('error', reject); | ||
} else { | ||
request.end(httpRequest.unchunkedBody); | ||
} | ||
}) | ||
.then( | ||
function(httpExchange) { | ||
expect(expectedResponseError, 'to be undefined'); | ||
return expect(httpExchange, 'to satisfy', { response: value }); | ||
}, | ||
function(err) { | ||
if (request) { | ||
request.abort(); | ||
} | ||
if (expectedResponseError) { | ||
expect(err, 'to equal', expectedResponseError); | ||
} else if (err.code) { | ||
// Socket or DNS error | ||
expect.fail({ | ||
diff: function(output) { | ||
output.error(err.message); | ||
return output; | ||
}, | ||
code: err.code | ||
}); | ||
} else { | ||
throw err; | ||
} | ||
} | ||
) | ||
.then(function() { | ||
return context; | ||
}); | ||
} | ||
} | ||
); | ||
} | ||
}; | ||
module.exports.messy = messy; |
{ | ||
"name": "unexpected-http", | ||
"version": "6.1.0", | ||
"version": "6.1.1", | ||
"description": "Unexpected plugin for testing http servers", | ||
@@ -11,6 +11,6 @@ "main": "lib/unexpectedHttp.js", | ||
"lint": "eslint .", | ||
"test": "npm run test-node && npm run test-browser && npm run lint", | ||
"test": "npm run test-node && npm run test-browser", | ||
"test-browser": "npm run prepublish && karma start --single-run", | ||
"test-node": "mocha --require unexpected-markdown test/*.js `find documentation -name '*.md'`", | ||
"travis": "npm test && npm run coverage && (<coverage/lcov.info coveralls || true)", | ||
"ci": "npm test && npm run lint && npm run coverage", | ||
"coverage": "NODE_ENV=development nyc --reporter=lcov --reporter=text npm run test-node && echo google-chrome coverage/lcov-report/index.html", | ||
@@ -53,7 +53,8 @@ "prepublish": "browserify -p bundle-collapser/plugin -e lib/unexpectedHttp -s unexpectedHttp > unexpectedHttp.min.js", | ||
"devDependencies": { | ||
"browserify": "^13.1.0", | ||
"browserify": "^16.2.3", | ||
"bundle-collapser": "^1.1.0", | ||
"coveralls": "^3.0.0", | ||
"eslint": "^5.0.1", | ||
"eslint-config-onelint": "^4.0.0", | ||
"eslint-config-pretty-standard": "^2.0.0", | ||
"eslint-plugin-prettier": "^3.0.1", | ||
"karma": "^3.1.4", | ||
@@ -65,5 +66,6 @@ "karma-chrome-launcher": "^2.2.0", | ||
"nyc": "^13.0.1", | ||
"prettier": "^1.15.3", | ||
"puppeteer": "^1.11.0", | ||
"semver": "^5.0.3", | ||
"stream-http": "^2.4.0", | ||
"stream-http": "^3.0.0", | ||
"unexpected": "^11.0.0-4", | ||
@@ -70,0 +72,0 @@ "unexpected-documentation-site-generator": "^5.0.0", |
Sorry, the diff of this file is too big to display
1632114
39788
19