diff --git a/index.js b/index.js
index f628e42..7fdba82 100644
--- a/index.js
+++ b/index.js
@@ -28,9 +28,12 @@ var DOUBLE_SPACE_REGEXP = /\x20{2}/g
var NEWLINE_REGEXP = /\n/g
/* istanbul ignore next */
-var defer = typeof setImmediate === 'function'
- ? setImmediate
- : function (fn) { process.nextTick(fn.bind.apply(fn, arguments)) }
+var defer =
+ typeof setImmediate === 'function'
+ ? setImmediate
+ : function (fn) {
+ process.nextTick(fn.bind.apply(fn, arguments))
+ }
var isFinished = onFinished.isFinished
/**
@@ -41,20 +44,22 @@ var isFinished = onFinished.isFinished
*/
function createHtmlDocument (message) {
- var body = escapeHtml(message)
- .replace(NEWLINE_REGEXP, '
')
- .replace(DOUBLE_SPACE_REGEXP, ' ')
+ var body = escapeHtml(message).replace(NEWLINE_REGEXP, '
').replace(DOUBLE_SPACE_REGEXP, ' ')
- return '\n' +
+ return (
+ '\n' +
'\n' +
'
' + body + '\n' + + '
' + + body + + '\n' + '\n' + '\n' + ) } /** @@ -175,6 +180,13 @@ function getErrorMessage (err, status, env) { // use err.stack, which typically includes err.message msg = err.stack + // if error cause included + if (err && err.cause && err.cause.stack) { + msg += '\n[cause]: ' + err.cause.stack + } else if (err && err.stack) { + msg += '\n[stack]: ' + err.stack + } + // fallback to err.toString() when possible if (!msg && typeof err.toString === 'function') { msg = err.toString() @@ -253,9 +265,7 @@ function getResponseStatusCode (res) { */ function headersSent (res) { - return typeof res.headersSent !== 'boolean' - ? Boolean(res._header) - : res.headersSent + return typeof res.headersSent !== 'boolean' ? Boolean(res._header) : res.headersSent } /** diff --git a/test/test.js b/test/test.js index a815654..8975427 100644 --- a/test/test.js +++ b/test/test.js @@ -1,4 +1,3 @@ - var Buffer = require('safe-buffer').Buffer var finalhandler = require('..') var http = require('http') @@ -14,46 +13,60 @@ var shouldHaveStatusMessage = utils.shouldHaveStatusMessage var shouldNotHaveBody = utils.shouldNotHaveBody var shouldNotHaveHeader = utils.shouldNotHaveHeader -var describeStatusMessage = !/statusMessage/.test(http.IncomingMessage.toString()) - ? describe.skip - : describe +var describeStatusMessage = !/statusMessage/.test(http.IncomingMessage.toString()) ? describe.skip : describe describe('finalhandler(req, res)', function () { describe('headers', function () { it('should ignore err.headers without status code', function (done) { - request(createServer(createError('oops!', { - headers: { 'X-Custom-Header': 'foo' } - }))) + request( + createServer( + createError('oops!', { + headers: { 'X-Custom-Header': 'foo' } + }) + ) + ) .get('/') .expect(shouldNotHaveHeader('X-Custom-Header')) .expect(500, done) }) it('should ignore err.headers with invalid res.status', function (done) { - request(createServer(createError('oops!', { - headers: { 'X-Custom-Header': 'foo' }, - status: 601 - }))) + request( + createServer( + createError('oops!', { + headers: { 'X-Custom-Header': 'foo' }, + status: 601 + }) + ) + ) .get('/') .expect(shouldNotHaveHeader('X-Custom-Header')) .expect(500, done) }) it('should ignore err.headers with invalid res.statusCode', function (done) { - request(createServer(createError('oops!', { - headers: { 'X-Custom-Header': 'foo' }, - statusCode: 601 - }))) + request( + createServer( + createError('oops!', { + headers: { 'X-Custom-Header': 'foo' }, + statusCode: 601 + }) + ) + ) .get('/') .expect(shouldNotHaveHeader('X-Custom-Header')) .expect(500, done) }) it('should include err.headers with err.status', function (done) { - request(createServer(createError('oops!', { - headers: { 'X-Custom-Header': 'foo=500', 'X-Custom-Header2': 'bar' }, - status: 500 - }))) + request( + createServer( + createError('oops!', { + headers: { 'X-Custom-Header': 'foo=500', 'X-Custom-Header2': 'bar' }, + status: 500 + }) + ) + ) .get('/') .expect('X-Custom-Header', 'foo=500') .expect('X-Custom-Header2', 'bar') @@ -61,20 +74,28 @@ describe('finalhandler(req, res)', function () { }) it('should include err.headers with err.statusCode', function (done) { - request(createServer(createError('too many requests', { - headers: { 'Retry-After': '5' }, - statusCode: 429 - }))) + request( + createServer( + createError('too many requests', { + headers: { 'Retry-After': '5' }, + statusCode: 429 + }) + ) + ) .get('/') .expect('Retry-After', '5') .expect(429, done) }) it('should ignore err.headers when not an object', function (done) { - request(createServer(createError('oops!', { - headers: 'foobar', - statusCode: 500 - }))) + request( + createServer( + createError('oops!', { + headers: 'foobar', + statusCode: 500 + }) + ) + ) .get('/') .expect(500, done) }) @@ -82,95 +103,131 @@ describe('finalhandler(req, res)', function () { describe('status code', function () { it('should 404 on no error', function (done) { - request(createServer()) - .get('/') - .expect(404, done) + request(createServer()).get('/').expect(404, done) }) it('should 500 on error', function (done) { - request(createServer(createError())) - .get('/') - .expect(500, done) + request(createServer(createError())).get('/').expect(500, done) }) it('should use err.statusCode', function (done) { - request(createServer(createError('nope', { - statusCode: 400 - }))) + request( + createServer( + createError('nope', { + statusCode: 400 + }) + ) + ) .get('/') .expect(400, done) }) it('should ignore non-error err.statusCode code', function (done) { - request(createServer(createError('created', { - statusCode: 201 - }))) + request( + createServer( + createError('created', { + statusCode: 201 + }) + ) + ) .get('/') .expect(500, done) }) it('should ignore non-numeric err.statusCode', function (done) { - request(createServer(createError('oops', { - statusCode: 'oh no' - }))) + request( + createServer( + createError('oops', { + statusCode: 'oh no' + }) + ) + ) .get('/') .expect(500, done) }) it('should use err.status', function (done) { - request(createServer(createError('nope', { - status: 400 - }))) + request( + createServer( + createError('nope', { + status: 400 + }) + ) + ) .get('/') .expect(400, done) }) it('should use err.status over err.statusCode', function (done) { - request(createServer(createError('nope', { - status: 400, - statusCode: 401 - }))) + request( + createServer( + createError('nope', { + status: 400, + statusCode: 401 + }) + ) + ) .get('/') .expect(400, done) }) it('should set status to 500 when err.status < 400', function (done) { - request(createServer(createError('oops', { - status: 202 - }))) + request( + createServer( + createError('oops', { + status: 202 + }) + ) + ) .get('/') .expect(500, done) }) it('should set status to 500 when err.status > 599', function (done) { - request(createServer(createError('oops', { - status: 601 - }))) + request( + createServer( + createError('oops', { + status: 601 + }) + ) + ) .get('/') .expect(500, done) }) it('should use err.statusCode over invalid err.status', function (done) { - request(createServer(createError('nope', { - status: 50, - statusCode: 410 - }))) + request( + createServer( + createError('nope', { + status: 50, + statusCode: 410 + }) + ) + ) .get('/') .expect(410, done) }) it('should ignore non-error err.status code', function (done) { - request(createServer(createError('created', { - status: 201 - }))) + request( + createServer( + createError('created', { + status: 201 + }) + ) + ) .get('/') .expect(500, done) }) it('should ignore non-numeric err.status', function (done) { - request(createServer(createError('oops', { - status: 'oh no' - }))) + request( + createServer( + createError('oops', { + status: 'oh no' + }) + ) + ) .get('/') .expect(500, done) }) @@ -178,10 +235,7 @@ describe('finalhandler(req, res)', function () { describeStatusMessage('status message', function () { it('should be "Not Found" on no error', function (done) { - request(createServer()) - .get('/') - .expect(shouldHaveStatusMessage('Not Found')) - .expect(404, done) + request(createServer()).get('/').expect(shouldHaveStatusMessage('Not Found')).expect(404, done) }) it('should be "Internal Server Error" on error', function (done) { @@ -192,9 +246,13 @@ describe('finalhandler(req, res)', function () { }) it('should be "Bad Request" when err.statusCode = 400', function (done) { - request(createServer(createError('oops', { - status: 400 - }))) + request( + createServer( + createError('oops', { + status: 400 + }) + ) + ) .get('/') .expect(shouldHaveStatusMessage('Bad Request')) .expect(400, done) @@ -222,7 +280,7 @@ describe('finalhandler(req, res)', function () { it('should escape method and pathname characters', function (done) { rawrequest(createServer()) - .get('/
Cannot GET \/%3Cla'me%3E<\/pre>/, done) }) @@ -263,25 +321,15 @@ describe('finalhandler(req, res)', function () { }) it('should handle HEAD', function (done) { - request(createServer()) - .head('/foo') - .expect(404) - .expect(shouldNotHaveBody()) - .end(done) + request(createServer()).head('/foo').expect(404).expect(shouldNotHaveBody()).end(done) }) it('should include X-Content-Type-Options header', function (done) { - request(createServer()) - .get('/foo') - .expect('X-Content-Type-Options', 'nosniff') - .expect(404, done) + request(createServer()).get('/foo').expect('X-Content-Type-Options', 'nosniff').expect(404, done) }) it('should include Content-Security-Policy header', function (done) { - request(createServer()) - .get('/foo') - .expect('Content-Security-Policy', "default-src 'none'") - .expect(404, done) + request(createServer()).get('/foo').expect('Content-Security-Policy', "default-src 'none'").expect(404, done) }) it('should not hang/error if there is a request body', function (done) { @@ -340,9 +388,11 @@ describe('finalhandler(req, res)', function () { var err = createError('boom!', { status: 501 }) - request(createServer(err, { - env: 'production' - })) + request( + createServer(err, { + env: 'production' + }) + ) .get('/foo') .expect(501, /Not Implemented<\/pre>/, done) }) @@ -399,9 +449,7 @@ describe('finalhandler(req, res)', function () { done(new Error('oops')) }) - request(server) - .get('/foo') - .expect(503, done) + request(server).get('/foo').expect(503, done) }) it('should convert to 500 is not a number', function (done) { @@ -411,9 +459,7 @@ describe('finalhandler(req, res)', function () { done(new Error('oops')) }) - request(server) - .get('/foo') - .expect(500, done) + request(server).get('/foo').expect(500, done) }) it('should override with err.status', function (done) { @@ -426,18 +472,18 @@ describe('finalhandler(req, res)', function () { done(err) }) - request(server) - .get('/foo') - .expect(414, done) + request(server).get('/foo').expect(414, done) }) it('should default body to status message in production', function (done) { var err = createError('boom!', { status: 509 }) - request(createServer(err, { - env: 'production' - })) + request( + createServer(err, { + env: 'production' + }) + ) .get('/foo') .expect(509, /Bandwidth Limit Exceeded<\/pre>/, done) }) @@ -451,9 +497,7 @@ describe('finalhandler(req, res)', function () { done(new Error('oops')) }) - request(server) - .get('/foo') - .expect(500, done) + request(server).get('/foo').expect(500, done) }) }) }) @@ -466,11 +510,7 @@ describe('finalhandler(req, res)', function () { done() }) - request(server) - .get('/foo') - .expect(404) - .expect('Server', 'foobar') - .end(done) + request(server).get('/foo').expect(404).expect('Server', 'foobar').end(done) }) it('should override content-type and length', function (done) { @@ -520,9 +560,7 @@ describe('finalhandler(req, res)', function () { }) }) - request(server) - .get('/foo') - .expect(301, '01', done) + request(server).get('/foo').expect(301, '01', done) }) it('should terminate on error', function (done) { @@ -531,10 +569,12 @@ describe('finalhandler(req, res)', function () { res.statusCode = 301 res.write('0') process.nextTick(function () { - done(createError('too many requests', { - status: 429, - headers: { 'Retry-After': '5' } - })) + done( + createError('too many requests', { + status: 429, + headers: { 'Retry-After': '5' } + }) + ) res.end('1') }) }) @@ -577,4 +617,17 @@ describe('finalhandler(req, res)', function () { }) }) }) + + describe('should display cause in the Error output', function () { + it('should return error message with stack trace in development', function (done) { + process.env.NODE_ENV = 'development' + const err = new Error('foo', { cause: new Error('bar') }) + + const server = createServer(err) + + request(server) + .get('/') + .expect(500, /[Error: bar]/, done) + }) + }) })