node-mocks-http
Advanced tools
Comparing version 1.5.2 to 1.5.3
@@ -0,1 +1,26 @@ | ||
v 1.5.3 | ||
------- | ||
* Add `.format` to the `mockResponse` object [PR #94][94] | ||
* Add `.location` to the `mockResponse` object [PR #96][96] | ||
* Add API method, `createMocks` to create both mocks with correct references | ||
[96]: https://github.com/howardabrams/node-mocks-http/issues/96 | ||
[94]: https://github.com/howardabrams/node-mocks-http/issues/94 | ||
v 1.5.2 | ||
------- | ||
* Add case insensitive response headers [#85][85] | ||
* Fix behavior of `mockResponse.writeHead` [#92][92] | ||
* Add support for statusMessage [#84][84] | ||
* Fix issue with `req.param` not returning when false [#82][82] | ||
* Other bug fixes | ||
[92]: https://github.com/howardabrams/node-mocks-http/issues/92 | ||
[84]: https://github.com/howardabrams/node-mocks-http/issues/84 | ||
[82]: https://github.com/howardabrams/node-mocks-http/issues/82 | ||
[85]: https://github.com/howardabrams/node-mocks-http/issues/85 | ||
v 1.5.1 | ||
@@ -2,0 +27,0 @@ ------- |
@@ -13,3 +13,21 @@ 'use strict'; | ||
/** | ||
* Creates linked req and res objects. Enables using methods that require both | ||
* objects to interact, for example res.format. | ||
* | ||
* @param {Object} reqOpts Options for req creation, see | ||
* @mockRequest.createRequest | ||
* @param {Object} resOpts Options for res creation, see | ||
* @mockResponse.createResponse | ||
* @return {Object} Object with both mocks: { req, res } | ||
*/ | ||
var createRequestResponse = function (reqOpts, resOpts) { | ||
var req = request.createRequest(reqOpts); | ||
var res = response.createResponse(Object.assign({}, resOpts, { req: req })); | ||
return { req: req, res: res }; | ||
}; | ||
exports.createRequest = request.createRequest; | ||
exports.createResponse = response.createResponse; | ||
exports.createMocks = createRequestResponse; |
@@ -34,2 +34,3 @@ 'use strict'; | ||
var typeis = require('type-is'); | ||
var accepts = require('accepts'); | ||
var events = require('events'); | ||
@@ -80,2 +81,13 @@ | ||
mockRequest.query = require('querystring').parse(mockRequest.url.split('?')[1]); | ||
if (!mockRequest.query.hasOwnProperty) { | ||
Object.defineProperty( | ||
mockRequest.query, | ||
'hasOwnProperty', | ||
{ | ||
enumerable: false, | ||
value: Object.hasOwnProperty.bind(mockRequest.query) | ||
} | ||
); | ||
} | ||
} | ||
@@ -159,2 +171,28 @@ | ||
/** | ||
* Function: accepts | ||
* | ||
* Checks for matching content types in the Accept header. | ||
* | ||
* Examples: | ||
* | ||
* mockRequest.headers['accept'] = 'application/json' | ||
* | ||
* mockRequest.accepts('json'); | ||
* // => 'json' | ||
* | ||
* mockRequest.accepts('html'); | ||
* // => false | ||
* | ||
* mockRequest.accepts(['html', 'json']); | ||
* // => 'json' | ||
* | ||
* @param {String|String[]} types Mime type(s) to check against | ||
* @return {String|false} Matching type or false if no match. | ||
*/ | ||
mockRequest.accepts = function(types) { | ||
var Accepts = accepts(mockRequest); | ||
return Accepts.type(types); | ||
}; | ||
/** | ||
* Function: param | ||
@@ -342,5 +380,4 @@ * | ||
return mockRequest; | ||
} | ||
module.exports.createRequest = createRequest; |
@@ -57,2 +57,3 @@ 'use strict'; | ||
var mockRequest = options.req; | ||
// create mockResponse | ||
@@ -67,2 +68,3 @@ | ||
mockResponse.cookies = {}; | ||
mockResponse.headersSent = false; | ||
@@ -104,2 +106,12 @@ mockResponse.cookie = function(name, value, opt) { | ||
if (mockResponse.headersSent) { | ||
// Node docs: "This method must only be called once on a message" | ||
// but it doesn't error if you do call it after first chunk of body is sent | ||
// so we shouldn't throw here either (although it's a bug in the code). | ||
// We return without updating since in real life it's just possible the double call didn't | ||
// completely corrupt the response (for example not using chunked encoding due to HTTP/1.0 client) | ||
// and in this case the client will see the _original_ headers. | ||
return; | ||
} | ||
mockResponse.statusCode = statusCode; | ||
@@ -127,5 +139,7 @@ | ||
/** | ||
* The 'send' function from node's HTTP API that returns data | ||
* The 'send' function from restify's Response API that returns data | ||
* to the client. Can be called multiple times. | ||
* | ||
* @see http://mcavage.me/node-restify/#response-api | ||
* | ||
* @param data The data to return. Must be a string. | ||
@@ -199,2 +213,4 @@ */ | ||
mockResponse.headersSent = true; | ||
mockResponse.emit('send'); | ||
@@ -321,3 +337,3 @@ mockResponse.emit('end'); | ||
*/ | ||
mockResponse.contentType = mockResponse.type = function(type){ | ||
mockResponse.contentType = mockResponse.type = function(type) { | ||
return mockResponse.set('Content-Type', type.indexOf('/') >= 0 ? type : mime.lookup(type)); | ||
@@ -327,2 +343,14 @@ }; | ||
/** | ||
* Set 'Location' response header. | ||
* | ||
* @see http://expressjs.com/en/api.html#res.location | ||
* | ||
* @param {String} location The location to set in the header. | ||
* @return {ServerResponse} For chaining | ||
*/ | ||
mockResponse.location = function(location) { | ||
return mockResponse.set('Location', location); | ||
}; | ||
/** | ||
* Function: write | ||
@@ -341,2 +369,4 @@ * | ||
mockResponse.headersSent = true; | ||
_data += data; | ||
@@ -364,2 +394,4 @@ | ||
mockResponse.headersSent = true; | ||
_endCalled = true; | ||
@@ -546,2 +578,38 @@ | ||
/** | ||
* Chooses the correct response function from the given supported types. | ||
* This method requires that the mockResponse object be initialized with a | ||
* mockRequest object reference, otherwise it will throw. @see createMocks. | ||
* | ||
* @param {Object} supported Object with formats to handler functions. | ||
* @return {Object} Whatever handler function returns. | ||
*/ | ||
mockResponse.format = function(supported) { | ||
supported = supported || {}; | ||
var types = Object.keys(supported); | ||
if (types.length === 0) { | ||
return mockResponse.sendStatus(406); | ||
} | ||
if (!mockRequest) { | ||
throw new Error( | ||
'Request object unavailable. Use createMocks or pass in a ' + | ||
'request object in createResponse to use format.' | ||
); | ||
} | ||
var accepted = mockRequest.accepts(types); | ||
if (accepted) { | ||
return supported[accepted](); | ||
} | ||
if (supported.default) { | ||
return supported.default(); | ||
} | ||
return mockResponse.sendStatus(406); | ||
}; | ||
// WritableStream.writable is not a function | ||
@@ -548,0 +616,0 @@ // mockResponse.writable = function() { |
@@ -5,3 +5,3 @@ { | ||
"description": "Mock 'http' objects for testing Express routing functions", | ||
"version": "1.5.2", | ||
"version": "1.5.3", | ||
"homepage": "https://github.com/howardabrams/node-mocks-http", | ||
@@ -44,2 +44,3 @@ "bugs": { | ||
"dependencies": { | ||
"accepts": "^1.3.3", | ||
"lodash.assign": "^4.0.6", | ||
@@ -46,0 +47,0 @@ "mime": "^1.3.4", |
@@ -113,2 +113,3 @@ [![node-mocks-http logo][nmh-logo]][nmh-url] | ||
`writableStream` | writable stream used by `response` object | `mockWritableStream` | ||
`req` | Request object being responded to | null | ||
@@ -137,2 +138,11 @@ > NOTE: The out-of-the-box mock event emitter included with `node-mocks-http` is | ||
### .createMocks() | ||
```js | ||
httpMocks.createMocks(reqOptions, resOptions) | ||
``` | ||
Merges `createRequest` and `createResponse`. Passes given options object to each | ||
constructor. | ||
## Design Decisions | ||
@@ -139,0 +149,0 @@ |
@@ -355,2 +355,23 @@ 'use strict'; | ||
describe('.accepts()', function() { | ||
var request; | ||
beforeEach(function() { | ||
request = mockRequest.createRequest({ headers: { accept: 'text/html' }}); | ||
}); | ||
it('returns type if the same as Accept header', function() { | ||
expect(request.accepts('text/html')).to.equal('text/html'); | ||
expect(request.accepts('html')).to.equal('html'); | ||
}); | ||
it('returns the first matching type of an array of types', function() { | ||
expect(request.accepts(['json', 'html'])).to.equal('html'); | ||
}); | ||
it('returns false when types dont match', function() { | ||
expect(request.accepts(['json', 'xml'])).to.equal(false); | ||
}); | ||
}); | ||
describe('.param()', function() { | ||
@@ -446,3 +467,2 @@ var request; | ||
}); | ||
}); | ||
@@ -449,0 +469,0 @@ |
@@ -10,2 +10,3 @@ 'use strict'; | ||
var mockResponse = require('../../lib/mockResponse'); | ||
var mockRequest = require('../../lib/mockRequest'); | ||
@@ -333,2 +334,19 @@ describe('mockResponse', function() { | ||
describe('.location()', function() { | ||
var response; | ||
beforeEach(function() { | ||
response = mockResponse.createResponse(); | ||
}); | ||
it('sets the Location header to the given path', function() { | ||
response.location('/a/nice/location'); | ||
expect(response.get('Location')).to.equal('/a/nice/location'); | ||
}); | ||
it('returns the response object', function() { | ||
expect(response.location('')).to.equal(response); | ||
}); | ||
}); | ||
describe('.set()/.header()', function() { | ||
@@ -550,3 +568,2 @@ var response; | ||
}); | ||
}); | ||
@@ -556,7 +573,56 @@ | ||
describe('.redirect()', function() { | ||
it('method should mimic Express Response.redirect()'); | ||
}); | ||
describe('.format()', function() { | ||
var response, request; | ||
beforeEach(function () { | ||
request = mockRequest.createRequest(); | ||
response = mockResponse.createResponse({ req: request }); | ||
}); | ||
it('sends 406 when given no supported formats', function() { | ||
response.format({}); | ||
expect(response.statusCode).to.equal(406); | ||
expect(response._getData()).to.equal('Not Acceptable'); | ||
}); | ||
it('throws when no request object is available', function() { | ||
response = mockResponse.createResponse(); | ||
expect(function() { | ||
response.format({ html: function() {} }); | ||
}).to.throw(Error, /Request object unavailable/); | ||
}); | ||
it('calls the handler for the closest accepted type', function() { | ||
var htmlSpy = sinon.spy(); | ||
var jsonSpy = sinon.spy(); | ||
request.headers.accept = 'application/json'; | ||
response.format({ html: htmlSpy, json: jsonSpy }); | ||
expect(htmlSpy).to.not.have.been.called; | ||
expect(jsonSpy).to.have.been.called; | ||
}); | ||
it('sends 406 when no match is found', function() { | ||
var htmlSpy = sinon.spy(); | ||
var jsonSpy = sinon.spy(); | ||
request.headers.accept = 'text/xml'; | ||
response.format({ html: htmlSpy, json: jsonSpy }); | ||
expect(htmlSpy).to.not.have.been.called; | ||
expect(jsonSpy).to.not.have.been.called; | ||
expect(response.statusCode).to.equal(406); | ||
}); | ||
it('runs default function if it exists and no match is found', function() { | ||
var defaultSpy = sinon.spy(); | ||
response.format({ default: defaultSpy }); | ||
expect(defaultSpy).to.have.been.called; | ||
}); | ||
}); | ||
}); | ||
@@ -600,2 +666,17 @@ | ||
it('updates the headersSent property of the response', function() { | ||
var headers = { 'x-header': 'test llama' }; | ||
response.writeHead(400, headers); | ||
// headers are only sent by node with first body byte | ||
expect(response.headersSent).to.equal(false); | ||
response.write('foo'); | ||
expect(response.headersSent).to.equal(true); | ||
// further updates to headers shouldn't really be reflected in mock headers | ||
// since these would be transmitted as part of the body (probably breaking chunked encoding) | ||
// in real life. | ||
response.writeHead(500, {'x-header': 'llama party'}); | ||
// Should still see same as before | ||
expect(response._getHeaders()).to.deep.equal(headers); | ||
}); | ||
it('works with statusMessage and headers as optional', function() { | ||
@@ -602,0 +683,0 @@ response.writeHead(400); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
137560
2985
218
4
+ Addedaccepts@^1.3.3
+ Addedaccepts@1.3.8(transitive)
+ Addednegotiator@0.6.3(transitive)