Skip to content

Commit

Permalink
feat: added display-errors & display-sections option
Browse files Browse the repository at this point in the history
  • Loading branch information
Gcaufy committed Dec 1, 2019
1 parent 55d27e6 commit 8b550b8
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 31 deletions.
11 changes: 10 additions & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,19 @@ module.exports = app => {
? config.errorPageUrl(err, this)
: config.errorPageUrl;

// If it's null, then use default isProd logic
let displayErrors = config.displayErrors === null ? !isProd(app) : config.displayErrors;

// It also can be a function
if (typeof displayErrors === 'function') {
displayErrors = displayErrors.call(app);
}

// keep the real response status
this.realStatus = status;
// don't respond any error message in production env
if (isProd(app)) {
// if displayErrors set false, or unset, then use default logic
if (!displayErrors) {
// 5xx
if (status >= 500) {
if (errorPageUrl) {
Expand Down
6 changes: 6 additions & 0 deletions config/config.default.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,10 @@ exports.onerror = {
appErrorFilter: null,
// default template path
templatePath: path.join(__dirname, '../lib/onerror_page.mustache'),
// Set displayErrors to true, to display erros.
// If it's not set, then use the default isProd logic for it.
displayErrors: null,
// Sections you want to show in error page.
// Default to show all sections.
displaySections: [ 'CodeFrames', 'Headers', 'Cookies', 'AppInfo' ],
};
58 changes: 36 additions & 22 deletions lib/error_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class ErrorView {
this.app = ctx.app;
this.assets = new Map();
this.viewTemplate = template;
this.displaySections = this.app.config.onerror.displaySections;
}

/**
Expand All @@ -41,8 +42,14 @@ class ErrorView {
});

data.request = this.serializeRequest();
data.appInfo = this.serializeAppInfo();

if (this.displaySections.indexOf('AppInfo') > -1) {
data.appInfo = this.serializeAppInfo();
}

this.displaySections.forEach(item => {
data['display' + item + 'Section'] = true;
});
return this.complieView(this.viewTemplate, data);
}

Expand Down Expand Up @@ -240,13 +247,17 @@ class ErrorView {
if (code) {
message = `${message} (code: ${code})`;
}
return {

const data = {
code,
message,
name: this.error.name,
status: this.error.status,
frames: stack instanceof Array ? stack.filter(frame => frame.getFileName()).map(frameFomatter) : [],
};
if (this.displaySections.indexOf('CodeFrames') > -1) {
data.frames = stack instanceof Array ? stack.filter(frame => frame.getFileName()).map(frameFomatter) : [];
}
return data;
}

/**
Expand All @@ -257,31 +268,34 @@ class ErrorView {
* @memberOf ErrorView
*/
serializeRequest() {
const headers = [];

Object.keys(this.request.headers).forEach(key => {
if (this._filterHeaders.includes(key)) {
return;
}
headers.push({
key,
value: this.request.headers[key],
});
});

const parsedCookies = cookie.parse(this.request.headers.cookie || '');
const cookies = Object.keys(parsedCookies).map(key => {
return { key, value: parsedCookies[key] };
});

return {
const data = {
url: this.request.url,
httpVersion: this.request.httpVersion,
method: this.request.method,
connection: this.request.headers.connection,
headers,
cookies,
};

if (this.displaySections.indexOf('Headers') > -1) {
const headers = [];
Object.keys(this.request.headers).forEach(key => {
if (this._filterHeaders.includes(key)) {
return;
}
headers.push({
key,
value: this.request.headers[key],
});
});
data.headers = headers;
}
if (this.displaySections.indexOf('Cookies') > -1) {
const parsedCookies = cookie.parse(this.request.headers.cookie || '');
data.cookies = Object.keys(parsedCookies).map(key => {
return { key, value: parsedCookies[key] };
});
}
return data;
}

/**
Expand Down
26 changes: 18 additions & 8 deletions lib/onerror_page.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@

<img class="error-logo" src="https://zos.alipayobjects.com/rmsportal/JFKAMfmPehWfhBPdCjrw.svg"/>

{{#displayCodeFramesSection}}
<div class="error-frames">
<div class="frame-preview is-hidden">
<div id="frame-file"></div>
Expand All @@ -593,8 +594,8 @@
<label for="frames-filter">Show all frames</label>
</div>

{{#frames}}
<div class="frames-list">
{{#frames}}
{{index}}
<div class="frame-row {{classes}}">
<div class="frame-row-filepath">
Expand All @@ -619,8 +620,8 @@
</div>
</div>
</div>
{{/displayCodeFramesSection}}
</section>

<section class="request-details">
<h2 class="request-title"> Request Details </h2>
<div class="table">
Expand All @@ -645,25 +646,33 @@
</div>
</div>


{{#displayHeadersSection}}
<h2 class="request-title"> Headers </h2>
<div class="table">
{{#request.headers}}
{{#request.headers}}
<div class="tr">
<div class="td title">{{ key }}</div>
<div class="td content">{{ value }}</div>
</div>
{{/request.headers}}
{{/request.headers}}
</div>
{{/displayHeadersSection}}


{{#displayCookiesSection}}
<h2 class="request-title"> Cookies </h2>
<div class="table">
{{#request.cookies}}
{{#request.cookies}}
<div class="tr">
<div class="td title">{{ key }}</div>
<div class="td content">{{ value }}</div>
</div>
{{/request.cookies}}
{{/request.cookies}}
</div>
{{/displayCookiesSection}}

{{#displayAppInfoSection}}
<h2 class="request-title"> AppInfo </h2>
<div class="table">
<div class="tr">
Expand All @@ -676,7 +685,8 @@
<pre class="line-numbers"><code class="language-json">{{ appInfo.config }}</code></pre>
</div>
</div>
</<div>
</div>
{{/displayAppInfoSection}}
</section>

<script type="text/javascript">
Expand Down Expand Up @@ -751,4 +761,4 @@ Prism.languages.typescript=Prism.languages.extend("javascript",{keyword:/\b(as|a
</script>
</section>
</body>
</html>
</html>
7 changes: 7 additions & 0 deletions test/fixtures/onerror-display-error/app/extend/context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

module.exports = {
get userId() {
throw new Error('you can`t get userId.');
},
};
7 changes: 7 additions & 0 deletions test/fixtures/onerror-display-error/app/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict';

module.exports = app => {
app.get('/500', function* () {
this.throw(500, 'hi, this custom 500 page');
});
};
6 changes: 6 additions & 0 deletions test/fixtures/onerror-display-error/config/config.default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
'use strict';

exports.keys = 'foo,bar';
exports.onerror = {
displayErrors: process.env.SHOW_ERRORS - 1 === 0,
};
3 changes: 3 additions & 0 deletions test/fixtures/onerror-display-error/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "onerror-display-error"
}
64 changes: 64 additions & 0 deletions test/onerror.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,70 @@ describe('test/onerror.test.js', () => {
});
});

describe('onerror.display-error', () => {
let app;
before(() => {
process.env.SHOW_ERRORS = 1;
mm.env('prod');
mm.consoleLevel('NONE');
app = mm.app({
baseDir: 'onerror-display-error',
});
return app.ready();
});
after(() => {
delete process.env.SHOW_ERRORS;
app.close();
});

it('should 500 full html', () => {
return app.httpRequest()
.get('/500')
.expect(500)
.expect(/hi, this custom 500 page/);
});

it('should works as a function', () => {
mm(app.config.onerror, 'displayErrors', () => false);
return app.httpRequest()
.get('/500')
.expect(res => {
assert.equal(res.text.includes('Internal Server Error'), true);
})
.expect(500);
});

it('should no headers in 500 full html', () => {
mm(app.config.onerror, 'displaySections', [ 'CodeFrames', 'Cookies', 'AppInfo' ]);
mm(app.config.onerror, 'displayErrors', true);
return app.httpRequest()
.get('/500')
.expect(res => {
assert.equal(res.text.includes('<h2 class="request-title"> Cookies </h2>'), true);
assert.equal(res.text.includes('<div class="error-frames">'), true);
assert.equal(res.text.includes('<h2 class="request-title"> AppInfo </h2>'), true);
assert.equal(res.text.includes('<h2 class="request-title"> Headers </h2>'), false);
})
.expect(500)
.expect(/hi, this custom 500 page/);
});

it('should only have headers in 500 full html', () => {
mm(app.config.onerror, 'displaySections', [ 'Headers' ]);
mm(app.config.onerror, 'displayErrors', true);
return app.httpRequest()
.get('/500')
.expect(res => {
assert.equal(res.text.includes('<h2 class="request-title"> Cookies </h2>'), false);
assert.equal(res.text.includes('<div class="error-frames">'), false);
assert.equal(res.text.includes('<h2 class="request-title"> AppInfo </h2>'), false);
assert.equal(res.text.includes('<h2 class="request-title"> Headers </h2>'), true);
})
.expect(500)
.expect(/hi, this custom 500 page/);
});
});

describe('appErrorFilter', () => {
let app;
before(() => {
Expand Down

0 comments on commit 8b550b8

Please sign in to comment.