strong-error-handler 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.travis.yml +1 -1
- package/CHANGES.md +16 -0
- package/lib/clone.js +2 -2
- package/lib/content-negotiation.js +12 -12
- package/lib/data-builder.js +3 -3
- package/lib/handler.js +12 -12
- package/lib/logger.js +4 -4
- package/lib/send-html.js +10 -10
- package/lib/send-json.js +2 -2
- package/lib/send-xml.js +2 -2
- package/package.json +9 -9
- package/test/handler.test.js +48 -48
package/.travis.yml
CHANGED
package/CHANGES.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
2019-10-12, Version 3.4.0
|
|
2
|
+
=========================
|
|
3
|
+
|
|
4
|
+
* chore: js2xmlparser to ^4.0.0 (Miroslav Bajtoš)
|
|
5
|
+
|
|
6
|
+
* chore: update dev-dependencies (mocha, supertest) (Miroslav Bajtoš)
|
|
7
|
+
|
|
8
|
+
* chore: update eslint & config to latest (Miroslav Bajtoš)
|
|
9
|
+
|
|
10
|
+
* chore: update strong-globalize to ^5.0.2 (Miroslav Bajtoš)
|
|
11
|
+
|
|
12
|
+
* chore: update debug to ^4.1.1 (Miroslav Bajtoš)
|
|
13
|
+
|
|
14
|
+
* feat: drop support for Node.js 6.x (Miroslav Bajtoš)
|
|
15
|
+
|
|
16
|
+
|
|
1
17
|
2019-09-30, Version 3.3.0
|
|
2
18
|
=========================
|
|
3
19
|
|
package/lib/clone.js
CHANGED
|
@@ -15,10 +15,10 @@ module.exports = cloneAllProperties;
|
|
|
15
15
|
function cloneAllProperties(data, err) {
|
|
16
16
|
data.name = err.name;
|
|
17
17
|
data.message = err.message;
|
|
18
|
-
for (
|
|
18
|
+
for (const p in err) {
|
|
19
19
|
if ((p in data)) continue;
|
|
20
20
|
data[p] = err[p];
|
|
21
21
|
}
|
|
22
22
|
// stack is appended last to ensure order is the same for response
|
|
23
23
|
data.stack = err.stack;
|
|
24
|
-
}
|
|
24
|
+
}
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
const accepts = require('accepts');
|
|
8
|
+
const debug = require('debug')('strong-error-handler:http-response');
|
|
9
|
+
const sendJson = require('./send-json');
|
|
10
|
+
const sendHtml = require('./send-html');
|
|
11
|
+
const sendXml = require('./send-xml');
|
|
12
|
+
const util = require('util');
|
|
13
13
|
|
|
14
14
|
module.exports = negotiateContentProducer;
|
|
15
15
|
|
|
@@ -23,14 +23,14 @@ module.exports = negotiateContentProducer;
|
|
|
23
23
|
* @returns {Function} Operation function with signature `fn(res, data)`
|
|
24
24
|
*/
|
|
25
25
|
function negotiateContentProducer(req, logWarning, options) {
|
|
26
|
-
|
|
26
|
+
const SUPPORTED_TYPES = [
|
|
27
27
|
'application/json', 'json',
|
|
28
28
|
'text/html', 'html',
|
|
29
29
|
'text/xml', 'xml',
|
|
30
30
|
];
|
|
31
31
|
|
|
32
32
|
options = options || {};
|
|
33
|
-
|
|
33
|
+
let defaultType = 'json';
|
|
34
34
|
|
|
35
35
|
// checking if user provided defaultType is supported
|
|
36
36
|
if (options.defaultType) {
|
|
@@ -52,9 +52,9 @@ function negotiateContentProducer(req, logWarning, options) {
|
|
|
52
52
|
// Accepts: */*, application/json, text/html ---> will resolve as application/json
|
|
53
53
|
// eg. Chrome accepts defaults to `text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*`
|
|
54
54
|
// In this case `resolvedContentType` will result as: `text/html` due to the order given
|
|
55
|
-
|
|
55
|
+
const resolvedContentType = accepts(req).types(SUPPORTED_TYPES);
|
|
56
56
|
debug('Resolved content-type', resolvedContentType);
|
|
57
|
-
|
|
57
|
+
let contentType = resolvedContentType || defaultType;
|
|
58
58
|
|
|
59
59
|
if (options.negotiateContentType === false) {
|
|
60
60
|
if (SUPPORTED_TYPES.indexOf(options.defaultType) > -1) {
|
|
@@ -71,13 +71,13 @@ function negotiateContentProducer(req, logWarning, options) {
|
|
|
71
71
|
// to receive _format from user's url param to overide the content type
|
|
72
72
|
// req.query (eg /api/Users/1?_format=json will overide content negotiation
|
|
73
73
|
// https://github.com/strongloop/strong-remoting/blob/ac3093dcfbb787977ca0229b0f672703859e52e1/lib/http-context.js#L643-L645
|
|
74
|
-
|
|
74
|
+
const query = req.query || {};
|
|
75
75
|
if (query._format) {
|
|
76
76
|
if (SUPPORTED_TYPES.indexOf(query._format) > -1) {
|
|
77
77
|
contentType = query._format;
|
|
78
78
|
} else {
|
|
79
79
|
// format passed through query but not supported
|
|
80
|
-
|
|
80
|
+
const msg = util.format('Response _format "%s" is not supported' +
|
|
81
81
|
'used "%s" instead"', query._format, defaultType);
|
|
82
82
|
logWarning(msg);
|
|
83
83
|
}
|
package/lib/data-builder.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const cloneAllProperties = require('../lib/clone.js');
|
|
9
|
+
const httpStatus = require('http-status');
|
|
10
10
|
|
|
11
11
|
module.exports = buildResponseData;
|
|
12
12
|
|
|
@@ -44,7 +44,7 @@ function buildResponseData(err, options) {
|
|
|
44
44
|
fillSafeFields(data, err, safeFields);
|
|
45
45
|
|
|
46
46
|
return data;
|
|
47
|
-
}
|
|
47
|
+
}
|
|
48
48
|
|
|
49
49
|
function serializeArrayOfErrors(errors, options) {
|
|
50
50
|
const details = errors.map(e => buildResponseData(e, options));
|
package/lib/handler.js
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const SG = require('strong-globalize');
|
|
10
10
|
SG.SetRootDir(path.resolve(__dirname, '..'));
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
const buildResponseData = require('./data-builder');
|
|
12
|
+
const debug = require('debug')('strong-error-handler');
|
|
13
|
+
const format = require('util').format;
|
|
14
|
+
const logToConsole = require('./logger');
|
|
15
|
+
const negotiateContentProducer = require('./content-negotiation');
|
|
16
16
|
|
|
17
17
|
function noop() {
|
|
18
18
|
}
|
|
@@ -29,13 +29,13 @@ function createStrongErrorHandler(options) {
|
|
|
29
29
|
debug('Initializing with options %j', options);
|
|
30
30
|
|
|
31
31
|
// Log all errors via console.error (enabled by default)
|
|
32
|
-
|
|
32
|
+
const logError = options.log !== false ? logToConsole : noop;
|
|
33
33
|
|
|
34
34
|
return function strongErrorHandler(err, req, res, next) {
|
|
35
35
|
logError(req, err);
|
|
36
36
|
writeErrorToResponse(err, req, res, options);
|
|
37
37
|
};
|
|
38
|
-
}
|
|
38
|
+
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Writes thrown error to response
|
|
@@ -59,20 +59,20 @@ function writeErrorToResponse(err, req, res, options) {
|
|
|
59
59
|
if (!err.status && !err.statusCode && res.statusCode >= 400)
|
|
60
60
|
err.statusCode = res.statusCode;
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
const data = buildResponseData(err, options);
|
|
63
63
|
debug('Response status %s data %j', data.statusCode, data);
|
|
64
64
|
|
|
65
65
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
66
66
|
res.statusCode = data.statusCode;
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
const sendResponse = negotiateContentProducer(req, warn, options);
|
|
69
69
|
sendResponse(res, data);
|
|
70
70
|
|
|
71
71
|
function warn(msg) {
|
|
72
72
|
res.header('X-Warning', msg);
|
|
73
73
|
debug(msg);
|
|
74
74
|
}
|
|
75
|
-
}
|
|
75
|
+
}
|
|
76
76
|
|
|
77
77
|
exports = module.exports = createStrongErrorHandler;
|
|
78
78
|
exports.writeErrorToResponse = writeErrorToResponse;
|
package/lib/logger.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const format = require('util').format;
|
|
9
|
+
const g = require('strong-globalize')();
|
|
10
10
|
|
|
11
11
|
module.exports = function logToConsole(req, err) {
|
|
12
12
|
if (!Array.isArray(err)) {
|
|
@@ -15,9 +15,9 @@ module.exports = function logToConsole(req, err) {
|
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
const errMsg = g.f('Unhandled array of errors for request %s %s\n',
|
|
19
19
|
req.method, req.url);
|
|
20
|
-
|
|
20
|
+
const errors = err.map(formatError).join('\n');
|
|
21
21
|
console.error(errMsg, errors);
|
|
22
22
|
};
|
|
23
23
|
|
package/lib/send-html.js
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const ejs = require('ejs');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const assetDir = path.resolve(__dirname, '../views');
|
|
12
|
+
const compiledTemplates = {
|
|
13
13
|
// loading default template and stylesheet
|
|
14
14
|
default: loadDefaultTemplates(),
|
|
15
15
|
};
|
|
@@ -17,9 +17,9 @@ var compiledTemplates = {
|
|
|
17
17
|
module.exports = sendHtml;
|
|
18
18
|
|
|
19
19
|
function sendHtml(res, data, options) {
|
|
20
|
-
|
|
20
|
+
const toRender = {options: {}, data: data};
|
|
21
21
|
// TODO: ability to call non-default template functions from options
|
|
22
|
-
|
|
22
|
+
const body = compiledTemplates.default(toRender);
|
|
23
23
|
sendReponse(res, body);
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -30,14 +30,14 @@ function sendHtml(res, data, options) {
|
|
|
30
30
|
* @returns {Function} render function with signature fn(data);
|
|
31
31
|
*/
|
|
32
32
|
function compileTemplate(filepath) {
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
const options = {cache: true, filename: filepath};
|
|
34
|
+
const fileContent = fs.readFileSync(filepath, 'utf8');
|
|
35
35
|
return ejs.compile(fileContent, options);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// loads and cache default error templates
|
|
39
39
|
function loadDefaultTemplates() {
|
|
40
|
-
|
|
40
|
+
const defaultTemplate = path.resolve(assetDir, 'default-error.ejs');
|
|
41
41
|
return compileTemplate(defaultTemplate);
|
|
42
42
|
}
|
|
43
43
|
|
package/lib/send-json.js
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const safeStringify = require('fast-safe-stringify');
|
|
9
9
|
|
|
10
10
|
module.exports = function sendJson(res, data) {
|
|
11
|
-
|
|
11
|
+
const content = safeStringify({error: data});
|
|
12
12
|
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
13
13
|
res.end(content, 'utf-8');
|
|
14
14
|
};
|
package/lib/send-xml.js
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const js2xmlparser = require('js2xmlparser');
|
|
9
9
|
|
|
10
10
|
module.exports = function sendXml(res, data) {
|
|
11
|
-
|
|
11
|
+
const content = js2xmlparser.parse('error', data);
|
|
12
12
|
res.setHeader('Content-Type', 'text/xml; charset=utf-8');
|
|
13
13
|
res.end(content, 'utf-8');
|
|
14
14
|
};
|
package/package.json
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"name": "strong-error-handler",
|
|
3
3
|
"description": "Error handler for use in development and production environments.",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "3.
|
|
5
|
+
"version": "3.4.0",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": ">=
|
|
7
|
+
"node": ">=8"
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -19,20 +19,20 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@types/express": "^4.16.0",
|
|
21
21
|
"accepts": "^1.3.3",
|
|
22
|
-
"debug": "^
|
|
22
|
+
"debug": "^4.1.1",
|
|
23
23
|
"ejs": "^2.6.1",
|
|
24
24
|
"fast-safe-stringify": "^2.0.6",
|
|
25
25
|
"http-status": "^1.1.2",
|
|
26
|
-
"js2xmlparser": "^
|
|
27
|
-
"strong-globalize": "^
|
|
26
|
+
"js2xmlparser": "^4.0.0",
|
|
27
|
+
"strong-globalize": "^5.0.2"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"chai": "^4.1.2",
|
|
31
|
-
"eslint": "^
|
|
32
|
-
"eslint-config-loopback": "^
|
|
31
|
+
"eslint": "^6.5.1",
|
|
32
|
+
"eslint-config-loopback": "^13.1.0",
|
|
33
33
|
"express": "^4.16.3",
|
|
34
|
-
"mocha": "^
|
|
35
|
-
"supertest": "^
|
|
34
|
+
"mocha": "^6.2.1",
|
|
35
|
+
"supertest": "^4.0.2"
|
|
36
36
|
},
|
|
37
37
|
"browser": {
|
|
38
38
|
"strong-error-handler": false
|
package/test/handler.test.js
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
const cloneAllProperties = require('../lib/clone.js');
|
|
9
|
+
const debug = require('debug')('test');
|
|
10
|
+
const expect = require('chai').expect;
|
|
11
|
+
const express = require('express');
|
|
12
|
+
const strongErrorHandler = require('..');
|
|
13
|
+
const supertest = require('supertest');
|
|
14
|
+
const util = require('util');
|
|
15
15
|
|
|
16
16
|
describe('strong-error-handler', function() {
|
|
17
17
|
before(setupHttpServerAndClient);
|
|
@@ -27,7 +27,7 @@ describe('strong-error-handler', function() {
|
|
|
27
27
|
|
|
28
28
|
it('handles response headers already sent', function(done) {
|
|
29
29
|
givenErrorHandlerForError();
|
|
30
|
-
|
|
30
|
+
const handler = _requestHandler;
|
|
31
31
|
_requestHandler = function(req, res, next) {
|
|
32
32
|
res.end('empty');
|
|
33
33
|
process.nextTick(function() {
|
|
@@ -70,7 +70,7 @@ describe('strong-error-handler', function() {
|
|
|
70
70
|
|
|
71
71
|
it('handles error from `res.statusCode`', function(done) {
|
|
72
72
|
givenErrorHandlerForError();
|
|
73
|
-
|
|
73
|
+
const handler = _requestHandler;
|
|
74
74
|
_requestHandler = function(req, res, next) {
|
|
75
75
|
res.statusCode = 507;
|
|
76
76
|
handler(req, res, next);
|
|
@@ -84,7 +84,7 @@ describe('strong-error-handler', function() {
|
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
context('logging', function() {
|
|
87
|
-
|
|
87
|
+
let logs;
|
|
88
88
|
|
|
89
89
|
beforeEach(redirectConsoleError);
|
|
90
90
|
afterEach(restoreConsoleError);
|
|
@@ -129,7 +129,7 @@ describe('strong-error-handler', function() {
|
|
|
129
129
|
request.get('/api').end(function(err) {
|
|
130
130
|
if (err) return done(err);
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
const msg = logs[0];
|
|
133
133
|
// the request method
|
|
134
134
|
expect(msg).to.contain('GET');
|
|
135
135
|
// the request path
|
|
@@ -152,7 +152,7 @@ describe('strong-error-handler', function() {
|
|
|
152
152
|
request.get('/api').end(function(err) {
|
|
153
153
|
if (err) return done(err);
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
const msg = logs[0];
|
|
156
156
|
// the request method
|
|
157
157
|
expect(msg).to.contain('GET');
|
|
158
158
|
// the request path
|
|
@@ -171,17 +171,17 @@ describe('strong-error-handler', function() {
|
|
|
171
171
|
givenErrorHandlerForError('STRING ERROR', {log: true});
|
|
172
172
|
request.get('/').end(function(err) {
|
|
173
173
|
if (err) return done(err);
|
|
174
|
-
|
|
174
|
+
const msg = logs[0];
|
|
175
175
|
expect(msg).to.contain('STRING ERROR');
|
|
176
176
|
done();
|
|
177
177
|
});
|
|
178
178
|
});
|
|
179
179
|
|
|
180
|
-
|
|
180
|
+
const _consoleError = console.error;
|
|
181
181
|
function redirectConsoleError() {
|
|
182
182
|
logs = [];
|
|
183
183
|
console.error = function() {
|
|
184
|
-
|
|
184
|
+
const msg = util.format.apply(util, arguments);
|
|
185
185
|
logs.push(msg);
|
|
186
186
|
};
|
|
187
187
|
}
|
|
@@ -194,7 +194,7 @@ describe('strong-error-handler', function() {
|
|
|
194
194
|
|
|
195
195
|
context('JSON response', function() {
|
|
196
196
|
it('contains all error properties when debug=true', function(done) {
|
|
197
|
-
|
|
197
|
+
const error = new ErrorWithProps({
|
|
198
198
|
message: 'a test error message',
|
|
199
199
|
code: 'MACHINE_READABLE_CODE',
|
|
200
200
|
details: 'some details',
|
|
@@ -205,7 +205,7 @@ describe('strong-error-handler', function() {
|
|
|
205
205
|
requestJson().end(function(err, res) {
|
|
206
206
|
if (err) return done(err);
|
|
207
207
|
|
|
208
|
-
|
|
208
|
+
const expectedData = {
|
|
209
209
|
statusCode: 500,
|
|
210
210
|
message: 'a test error message',
|
|
211
211
|
name: 'ErrorWithProps',
|
|
@@ -222,7 +222,7 @@ describe('strong-error-handler', function() {
|
|
|
222
222
|
|
|
223
223
|
it('includes code property for 4xx status codes when debug=false',
|
|
224
224
|
function(done) {
|
|
225
|
-
|
|
225
|
+
const error = new ErrorWithProps({
|
|
226
226
|
statusCode: 400,
|
|
227
227
|
message: 'error with code',
|
|
228
228
|
name: 'ErrorWithCode',
|
|
@@ -233,7 +233,7 @@ describe('strong-error-handler', function() {
|
|
|
233
233
|
requestJson().end(function(err, res) {
|
|
234
234
|
if (err) return done(err);
|
|
235
235
|
|
|
236
|
-
|
|
236
|
+
const expectedData = {
|
|
237
237
|
statusCode: 400,
|
|
238
238
|
message: 'error with code',
|
|
239
239
|
name: 'ErrorWithCode',
|
|
@@ -247,7 +247,7 @@ describe('strong-error-handler', function() {
|
|
|
247
247
|
|
|
248
248
|
it('excludes code property for 5xx status codes when debug=false',
|
|
249
249
|
function(done) {
|
|
250
|
-
|
|
250
|
+
const error = new ErrorWithProps({
|
|
251
251
|
statusCode: 500,
|
|
252
252
|
code: 'MACHINE_READABLE_CODE',
|
|
253
253
|
});
|
|
@@ -256,7 +256,7 @@ describe('strong-error-handler', function() {
|
|
|
256
256
|
requestJson().end(function(err, res) {
|
|
257
257
|
if (err) return done(err);
|
|
258
258
|
|
|
259
|
-
|
|
259
|
+
const expectedData = {
|
|
260
260
|
statusCode: 500,
|
|
261
261
|
message: 'Internal Server Error',
|
|
262
262
|
};
|
|
@@ -268,12 +268,12 @@ describe('strong-error-handler', function() {
|
|
|
268
268
|
|
|
269
269
|
it('contains non-enumerable Error properties when debug=true',
|
|
270
270
|
function(done) {
|
|
271
|
-
|
|
271
|
+
const error = new Error('a test error message');
|
|
272
272
|
givenErrorHandlerForError(error, {debug: true});
|
|
273
273
|
requestJson().end(function(err, res) {
|
|
274
274
|
if (err) return done(err);
|
|
275
275
|
expect(res.body).to.have.property('error');
|
|
276
|
-
|
|
276
|
+
const resError = res.body.error;
|
|
277
277
|
expect(resError).to.have.property('name', 'Error');
|
|
278
278
|
expect(resError).to.have.property('message',
|
|
279
279
|
'a test error message');
|
|
@@ -283,7 +283,7 @@ describe('strong-error-handler', function() {
|
|
|
283
283
|
});
|
|
284
284
|
|
|
285
285
|
it('should allow setting safe fields when status=5xx', function(done) {
|
|
286
|
-
|
|
286
|
+
const error = new ErrorWithProps({
|
|
287
287
|
name: 'Error',
|
|
288
288
|
safeField: 'SAFE',
|
|
289
289
|
unsafeField: 'UNSAFE',
|
|
@@ -304,7 +304,7 @@ describe('strong-error-handler', function() {
|
|
|
304
304
|
});
|
|
305
305
|
|
|
306
306
|
it('safe fields falls back to existing data', function(done) {
|
|
307
|
-
|
|
307
|
+
const error = new ErrorWithProps({
|
|
308
308
|
name: 'Error',
|
|
309
309
|
isSafe: false,
|
|
310
310
|
});
|
|
@@ -322,7 +322,7 @@ describe('strong-error-handler', function() {
|
|
|
322
322
|
});
|
|
323
323
|
|
|
324
324
|
it('should allow setting safe fields when status=4xx', function(done) {
|
|
325
|
-
|
|
325
|
+
const error = new ErrorWithProps({
|
|
326
326
|
name: 'Error',
|
|
327
327
|
statusCode: 422,
|
|
328
328
|
safeField: 'SAFE',
|
|
@@ -344,7 +344,7 @@ describe('strong-error-handler', function() {
|
|
|
344
344
|
});
|
|
345
345
|
|
|
346
346
|
it('contains subset of properties when status=4xx', function(done) {
|
|
347
|
-
|
|
347
|
+
const error = new ErrorWithProps({
|
|
348
348
|
name: 'ValidationError',
|
|
349
349
|
message: 'The model instance is not valid.',
|
|
350
350
|
statusCode: 422,
|
|
@@ -370,7 +370,7 @@ describe('strong-error-handler', function() {
|
|
|
370
370
|
|
|
371
371
|
it('contains only safe info when status=5xx', function(done) {
|
|
372
372
|
// Mock an error reported by fs.readFile
|
|
373
|
-
|
|
373
|
+
const error = new ErrorWithProps({
|
|
374
374
|
name: 'Error',
|
|
375
375
|
message: 'ENOENT: no such file or directory, open "/etc/passwd"',
|
|
376
376
|
errno: -2,
|
|
@@ -394,7 +394,7 @@ describe('strong-error-handler', function() {
|
|
|
394
394
|
});
|
|
395
395
|
|
|
396
396
|
it('handles array argument as 500 when debug=false', function(done) {
|
|
397
|
-
|
|
397
|
+
const errors = [new Error('ERR1'), new Error('ERR2'), 'ERR STRING'];
|
|
398
398
|
givenErrorHandlerForError(errors);
|
|
399
399
|
|
|
400
400
|
requestJson().expect(500).end(function(err, res) {
|
|
@@ -521,9 +521,9 @@ describe('strong-error-handler', function() {
|
|
|
521
521
|
});
|
|
522
522
|
|
|
523
523
|
it('handles Error objects containing circular properties', function(done) {
|
|
524
|
-
|
|
524
|
+
const circularObject = {};
|
|
525
525
|
circularObject.recursiveProp = circularObject;
|
|
526
|
-
|
|
526
|
+
const error = new ErrorWithProps({
|
|
527
527
|
statusCode: 422,
|
|
528
528
|
message: 'The model instance is not valid.',
|
|
529
529
|
name: 'ValidationError',
|
|
@@ -550,7 +550,7 @@ describe('strong-error-handler', function() {
|
|
|
550
550
|
|
|
551
551
|
context('HTML response', function() {
|
|
552
552
|
it('contains all error properties when debug=true', function(done) {
|
|
553
|
-
|
|
553
|
+
const error = new ErrorWithProps({
|
|
554
554
|
message: 'a test error message',
|
|
555
555
|
details: 'some details',
|
|
556
556
|
extra: 'sensitive data',
|
|
@@ -607,7 +607,7 @@ describe('strong-error-handler', function() {
|
|
|
607
607
|
});
|
|
608
608
|
|
|
609
609
|
it('contains subset of properties when status=4xx', function(done) {
|
|
610
|
-
|
|
610
|
+
const error = new ErrorWithProps({
|
|
611
611
|
name: 'ValidationError',
|
|
612
612
|
message: 'The model instance is not valid.',
|
|
613
613
|
statusCode: 422,
|
|
@@ -618,7 +618,7 @@ describe('strong-error-handler', function() {
|
|
|
618
618
|
requestHTML()
|
|
619
619
|
.end(function(err, res) {
|
|
620
620
|
expect(res.statusCode).to.eql(422);
|
|
621
|
-
|
|
621
|
+
const body = res.error.text;
|
|
622
622
|
expect(body).to.match(/some details/);
|
|
623
623
|
expect(body).to.not.match(/sensitive data/);
|
|
624
624
|
expect(body).to.match(/<title>ValidationError<\/title>/);
|
|
@@ -629,7 +629,7 @@ describe('strong-error-handler', function() {
|
|
|
629
629
|
|
|
630
630
|
it('contains only safe info when status=5xx', function(done) {
|
|
631
631
|
// Mock an error reported by fs.readFile
|
|
632
|
-
|
|
632
|
+
const error = new ErrorWithProps({
|
|
633
633
|
name: 'Error',
|
|
634
634
|
message: 'ENOENT: no such file or directory, open "/etc/passwd"',
|
|
635
635
|
errno: -2,
|
|
@@ -642,7 +642,7 @@ describe('strong-error-handler', function() {
|
|
|
642
642
|
requestHTML()
|
|
643
643
|
.end(function(err, res) {
|
|
644
644
|
expect(res.statusCode).to.eql(500);
|
|
645
|
-
|
|
645
|
+
const body = res.error.text;
|
|
646
646
|
expect(body).to.not.match(/\/etc\/password/);
|
|
647
647
|
expect(body).to.not.match(/-2/);
|
|
648
648
|
expect(body).to.not.match(/ENOENT/);
|
|
@@ -662,7 +662,7 @@ describe('strong-error-handler', function() {
|
|
|
662
662
|
|
|
663
663
|
context('XML response', function() {
|
|
664
664
|
it('contains all error properties when debug=true', function(done) {
|
|
665
|
-
|
|
665
|
+
const error = new ErrorWithProps({
|
|
666
666
|
message: 'a test error message',
|
|
667
667
|
details: 'some details',
|
|
668
668
|
extra: 'sensitive data',
|
|
@@ -680,7 +680,7 @@ describe('strong-error-handler', function() {
|
|
|
680
680
|
});
|
|
681
681
|
|
|
682
682
|
it('contains subset of properties when status=4xx', function(done) {
|
|
683
|
-
|
|
683
|
+
const error = new ErrorWithProps({
|
|
684
684
|
name: 'ValidationError',
|
|
685
685
|
message: 'The model instance is not valid.',
|
|
686
686
|
statusCode: 422,
|
|
@@ -691,7 +691,7 @@ describe('strong-error-handler', function() {
|
|
|
691
691
|
requestXML()
|
|
692
692
|
.end(function(err, res) {
|
|
693
693
|
expect(res.statusCode).to.eql(422);
|
|
694
|
-
|
|
694
|
+
const body = res.error.text;
|
|
695
695
|
expect(body).to.match(/<details>some details<\/details>/);
|
|
696
696
|
expect(body).to.not.match(/<extra>sensitive data<\/extra>/);
|
|
697
697
|
expect(body).to.match(/<name>ValidationError<\/name>/);
|
|
@@ -704,7 +704,7 @@ describe('strong-error-handler', function() {
|
|
|
704
704
|
|
|
705
705
|
it('contains only safe info when status=5xx', function(done) {
|
|
706
706
|
// Mock an error reported by fs.readFile
|
|
707
|
-
|
|
707
|
+
const error = new ErrorWithProps({
|
|
708
708
|
name: 'Error',
|
|
709
709
|
message: 'ENOENT: no such file or directory, open "/etc/passwd"',
|
|
710
710
|
errno: -2,
|
|
@@ -717,7 +717,7 @@ describe('strong-error-handler', function() {
|
|
|
717
717
|
requestXML()
|
|
718
718
|
.end(function(err, res) {
|
|
719
719
|
expect(res.statusCode).to.eql(500);
|
|
720
|
-
|
|
720
|
+
const body = res.error.text;
|
|
721
721
|
expect(body).to.not.match(/\/etc\/password/);
|
|
722
722
|
expect(body).to.not.match(/-2/);
|
|
723
723
|
expect(body).to.not.match(/ENOENT/);
|
|
@@ -848,7 +848,7 @@ describe('strong-error-handler', function() {
|
|
|
848
848
|
});
|
|
849
849
|
|
|
850
850
|
it('does not modify "options" argument', function(done) {
|
|
851
|
-
|
|
851
|
+
const options = {log: false, debug: false};
|
|
852
852
|
givenErrorHandlerForError(new Error(), options);
|
|
853
853
|
request.get('/').end(function(err) {
|
|
854
854
|
if (err) return done(err);
|
|
@@ -858,7 +858,7 @@ describe('strong-error-handler', function() {
|
|
|
858
858
|
});
|
|
859
859
|
});
|
|
860
860
|
|
|
861
|
-
|
|
861
|
+
let app, _requestHandler, request, server;
|
|
862
862
|
function resetRequestHandler() {
|
|
863
863
|
_requestHandler = null;
|
|
864
864
|
}
|
|
@@ -874,7 +874,7 @@ function givenErrorHandlerForError(error, options) {
|
|
|
874
874
|
options.log = false;
|
|
875
875
|
}
|
|
876
876
|
|
|
877
|
-
|
|
877
|
+
const handler = strongErrorHandler(options);
|
|
878
878
|
_requestHandler = function(req, res, next) {
|
|
879
879
|
debug('Invoking strong-error-handler');
|
|
880
880
|
handler(error, req, res, next);
|
|
@@ -885,7 +885,7 @@ function setupHttpServerAndClient(done) {
|
|
|
885
885
|
app = express();
|
|
886
886
|
app.use(function(req, res, next) {
|
|
887
887
|
if (!_requestHandler) {
|
|
888
|
-
|
|
888
|
+
const msg = 'Error handler middleware was not setup in this test';
|
|
889
889
|
console.error(msg);
|
|
890
890
|
res.statusCode = 500;
|
|
891
891
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
@@ -907,7 +907,7 @@ function setupHttpServerAndClient(done) {
|
|
|
907
907
|
});
|
|
908
908
|
|
|
909
909
|
server = app.listen(0, function() {
|
|
910
|
-
|
|
910
|
+
const url = 'http://127.0.0.1:' + this.address().port;
|
|
911
911
|
debug('Test server listening on %s', url);
|
|
912
912
|
request = supertest(app);
|
|
913
913
|
done();
|
|
@@ -924,7 +924,7 @@ function stopHttpServerAndClient() {
|
|
|
924
924
|
|
|
925
925
|
function ErrorWithProps(props) {
|
|
926
926
|
this.name = props.name || 'ErrorWithProps';
|
|
927
|
-
for (
|
|
927
|
+
for (const p in props) {
|
|
928
928
|
this[p] = props[p];
|
|
929
929
|
}
|
|
930
930
|
|
|
@@ -936,7 +936,7 @@ function ErrorWithProps(props) {
|
|
|
936
936
|
util.inherits(ErrorWithProps, Error);
|
|
937
937
|
|
|
938
938
|
function getExpectedErrorData(err) {
|
|
939
|
-
|
|
939
|
+
const data = {};
|
|
940
940
|
cloneAllProperties(data, err);
|
|
941
941
|
return data;
|
|
942
942
|
}
|