Skip to content

Commit 1827cd9

Browse files
committed
fix: error stack missing message
1 parent 9c486ae commit 1827cd9

File tree

2 files changed

+104
-46
lines changed

2 files changed

+104
-46
lines changed

src/base_error.js

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,56 @@
66

77
var util = require('./util');
88

9-
/**
10-
* @private
11-
*/
12-
function getBaseErrorStack() {
13-
var stackObj = this;
14-
if (!stackObj.cache) {
15-
stackObj.cache = stackObj.stack;
16-
}
17-
return stackObj.cache;
18-
}
19-
209
/**
2110
* @private
2211
*
2312
* @method getBaseErrorStackFunc
24-
* @param {Object} error
25-
* @param {String} error.stack
2613
* @param {Object} stackObj
27-
* @param {String} [stackObj.stack]
14+
* @param {String} [stackObj.stack='']
15+
* @param {Object} [preError]
16+
* @param {String} [preError.stack='']
2817
* @return {Function}
2918
*/
30-
function getBaseErrorStackFunc(error, stackObj) {
19+
function getBaseErrorStackFunc(stackObj, preError) {
3120
var cache;
3221
return function() {
22+
var baseError = this;
3323
if (!cache) {
34-
cache = (stackObj.stack || '') + this.ERROR_STACK_SEPARATOR + error.stack;
24+
if (preError) {
25+
cache = util.get(stackObj, 'stack', '') +
26+
baseError.ERROR_STACK_SEPARATOR +
27+
util.get(preError, 'stack', '');
28+
} else {
29+
cache = util.get(stackObj, 'stack', '');
30+
}
3531
}
3632
return cache;
3733
};
3834
}
3935

36+
37+
/**
38+
* Assign stack property to BaseError instance.
39+
*
40+
* @private
41+
*
42+
* @side_effect baseError
43+
* @method assignStack
44+
* @param {BaseError} baseError
45+
* @param {Object} stackObj
46+
* @param {String} [stackObj.stack='']
47+
* @param {Object} [preError]
48+
* @param {String} [preError.stack='']
49+
* @return {undefined}
50+
*/
51+
function assignStack(baseError, stackObj, preError) {
52+
Object.defineProperty(baseError, 'stack', {
53+
configurable: true,
54+
enumerable: true,
55+
get: getBaseErrorStackFunc(stackObj, preError),
56+
});
57+
}
58+
4059
/**
4160
* You should define your error class which inherits the `BaseError` class
4261
*
@@ -93,13 +112,10 @@ function BaseError() {
93112
}
94113
}
95114

115+
96116
if (self.captureStackTrace) {
97117
Error.captureStackTrace(stackObj, self.constructor);
98-
Object.defineProperty(self, 'stack', {
99-
configurable: true,
100-
enumerable: true,
101-
get: getBaseErrorStack.bind(stackObj),
102-
});
118+
assignStack(self, stackObj);
103119
}
104120

105121
if (error) {
@@ -114,14 +130,15 @@ function BaseError() {
114130
}
115131

116132
if (error.stack) {
117-
Object.defineProperty(self, 'stack', {
118-
configurable: true,
119-
enumerable: true,
120-
get: getBaseErrorStackFunc(error, stackObj),
121-
});
133+
assignStack(self, stackObj, error);
122134
}
123135
}
124136

137+
// For stack takes with error message
138+
// see https://github.com/nodejs/node/issues/5675#issuecomment-203966051
139+
stackObj.name = this.name;
140+
stackObj.message = message;
141+
125142
self.meta = meta;
126143
self.message = message;
127144
}

test/cases/base_error.js

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
describe('#base_error', function() {
44
var BaseError = require('../../src/base_error');
5-
var should = require('should');
65

76
function checkKeys(err) {
87
err.should.have.keys(['meta', 'message', 'stack']);
@@ -14,29 +13,35 @@ describe('#base_error', function() {
1413
err.name.should.equal('BaseError');
1514
err.meta.should.be.an.Object();
1615
err.message.should.equal(message);
17-
err.stack.should.be.a.String();
18-
should.not.exist(err.stack.match(/\==== Pre-Error-Stack ====/g));
16+
err.stack.should.be.a.String()
17+
.and.not.containEql(/\==== Pre-Error-Stack ====/g);
18+
err.stack.indexOf('BaseError: ' + message).should.equal(0);
1919
checkKeys(err);
2020
});
2121

2222
it('new BaseError(message, param1, param2...paramN)', function() {
23+
var targetMessage = 'hello! this a BaseError';
2324
var err = new BaseError('%s! this a %s', 'hello', 'BaseError');
2425
err.name.should.equal('BaseError');
25-
err.message.should.equal('hello! this a BaseError');
26-
err.stack.should.be.a.String();
27-
should.not.exist(err.stack.match(/\==== Pre-Error-Stack ====/g));
26+
err.message.should.equal(targetMessage);
27+
err.stack.should.be.a.String()
28+
.and.not.containEql(/\==== Pre-Error-Stack ====/g);
29+
err.stack.indexOf('BaseError: ' + targetMessage).should.equal(0);
2830
checkKeys(err);
2931
});
3032

3133
it('new BaseError(meta, message)', function() {
3234
var message = 'this a BaseError';
3335
var meta = {a: 1};
3436
var err = new BaseError(meta, message);
37+
var targetMessage = message;
38+
3539
err.name.should.equal('BaseError');
3640
err.meta.should.equal(meta);
3741
err.message.should.equal(message);
38-
err.stack.should.be.a.String();
39-
should.not.exist(err.stack.match(/\==== Pre-Error-Stack ====/g));
42+
err.stack.should.be.a.String()
43+
.and.not.containEql(/\==== Pre-Error-Stack ====/g);
44+
err.stack.indexOf('BaseError: ' + targetMessage).should.equal(0);
4045
checkKeys(err);
4146
});
4247

@@ -45,10 +50,13 @@ describe('#base_error', function() {
4550
error.meta = {a: 1};
4651
var message = 'this a BaseError';
4752
var err = new BaseError(error, message);
53+
var targetMessage = message;
54+
4855
err.name.should.equal('BaseError');
4956
err.meta.should.deepEqual(error.meta);
5057
err.message.should.equal(message);
5158
err.stack.should.be.a.String();
59+
err.stack.indexOf('BaseError: ' + targetMessage).should.equal(0);
5260
err.stack.match(/\==== Pre-Error-Stack ====/g).length.should.equal(1);
5361
checkKeys(err);
5462
});
@@ -58,12 +66,14 @@ describe('#base_error', function() {
5866
var error = new Error(_message);
5967
error.meta = {a: 3, b: 2};
6068
var message = 'this a BaseError';
69+
var targetMessage = message + ' && ' + _message;
6170
var meta = {a: 1};
6271
var err = new BaseError(error, meta, message);
6372
err.name.should.equal('BaseError');
6473
err.meta.should.deepEqual({a: 1, b: 2});
65-
err.message.should.equal(message + ' && ' + _message);
74+
err.message.should.equal(targetMessage);
6675
err.stack.should.be.a.String();
76+
err.stack.indexOf('BaseError: ' + targetMessage).should.equal(0);
6777
err.stack.match(/\==== Pre-Error-Stack ====/g).length.should.equal(1);
6878
checkKeys(err);
6979
});
@@ -73,12 +83,14 @@ describe('#base_error', function() {
7383
var error = new Error(_message);
7484
error.meta = {a: 3, b: 2};
7585
var message = 'this a BaseError';
86+
var targetMessage = message + ' && ' + _message;
7687
var meta = {a: 1};
7788
var err = new BaseError(meta, error, message);
7889
err.name.should.equal('BaseError');
7990
err.meta.should.deepEqual({a: 1, b: 2});
80-
err.message.should.equal(message + ' && ' + _message);
91+
err.message.should.equal(targetMessage);
8192
err.stack.should.be.a.String();
93+
err.stack.indexOf('BaseError: ' + targetMessage).should.equal(0);
8294
err.stack.match(/\==== Pre-Error-Stack ====/g).length.should.equal(1);
8395
checkKeys(err);
8496
});
@@ -90,10 +102,13 @@ describe('#base_error', function() {
90102
var message = '%s! this a %s';
91103
var meta = {a: 1};
92104
var err = new BaseError(meta, error, message, 'hello', 'BaseError');
105+
var targetMessage = 'hello! this a BaseError && ' + _message;
106+
93107
err.name.should.equal('BaseError');
94108
err.meta.should.deepEqual({a: 1, b: 2});
95-
err.message.should.equal('hello! this a BaseError && ' + _message);
109+
err.message.should.equal(targetMessage);
96110
err.stack.should.be.a.String();
111+
err.stack.indexOf('BaseError: ' + targetMessage).should.equal(0);
97112
err.stack.match(/\==== Pre-Error-Stack ====/g).length.should.equal(1);
98113
checkKeys(err);
99114
});
@@ -102,35 +117,44 @@ describe('#base_error', function() {
102117
var error;
103118
var message = 'this a BaseError';
104119
var err = new BaseError(error, message);
120+
var targetMessage = message;
121+
105122
err.name.should.equal('BaseError');
106123
err.meta.should.deepEqual({});
107124
err.message.should.equal(message);
108-
err.stack.should.be.a.String();
109-
should.not.exist(err.stack.match(/\==== Pre-Error-Stack ====/g));
125+
err.stack.should.be.a.String()
126+
.and.not.containEql(/\==== Pre-Error-Stack ====/g);
127+
err.stack.indexOf('BaseError: ' + targetMessage).should.equal(0);
110128
checkKeys(err);
111129
});
112130

113131
it('new BaseError(null, message) should equal new BaseError(message)', function() {
114132
var error = null;
115133
var message = 'this a BaseError';
116134
var err = new BaseError(error, message);
135+
var targetMessage = message;
136+
117137
err.name.should.equal('BaseError');
118138
err.meta.should.deepEqual({});
119139
err.message.should.equal(message);
120-
err.stack.should.be.a.String();
121-
should.not.exist(err.stack.match(/\==== Pre-Error-Stack ====/g));
140+
err.stack.should.be.a.String()
141+
.and.not.containEql(/\==== Pre-Error-Stack ====/g);
142+
err.stack.indexOf('BaseError: ' + targetMessage).should.equal(0);
122143
checkKeys(err);
123144
});
124145

125146
it('new BaseError(undefined, undefined, message) should equal new BaseError(message)', function() {
126147
var error, meta;
127148
var message = 'this a BaseError';
128149
var err = new BaseError(error, meta, message);
150+
var targetMessage = message;
151+
129152
err.name.should.equal('BaseError');
130153
err.meta.should.deepEqual({});
131154
err.message.should.equal(message);
132-
err.stack.should.be.a.String();
133-
should.not.exist(err.stack.match(/\==== Pre-Error-Stack ====/g));
155+
err.stack.should.be.a.String()
156+
.and.not.containEql(/\==== Pre-Error-Stack ====/g);
157+
err.stack.indexOf('BaseError: ' + targetMessage).should.equal(0);
134158
checkKeys(err);
135159
});
136160

@@ -139,11 +163,14 @@ describe('#base_error', function() {
139163
var meta;
140164
var message = 'this a BaseError';
141165
var err = new BaseError(error, meta, message);
166+
var targetMessage = message;
167+
142168
err.name.should.equal('BaseError');
143169
err.meta.should.deepEqual({});
144170
err.message.should.equal(message);
145-
err.stack.should.be.a.String();
146-
should.not.exist(err.stack.match(/\==== Pre-Error-Stack ====/g));
171+
err.stack.should.be.a.String()
172+
.and.not.containEql(/\==== Pre-Error-Stack ====/g);
173+
err.stack.indexOf('BaseError: ' + targetMessage).should.equal(0);
147174
checkKeys(err);
148175
});
149176

@@ -185,10 +212,24 @@ describe('#base_error', function() {
185212
var secondErr = new BaseError(firstErr, secondMeta, 'the second error');
186213
var thirdMeta = {b: '2', c: [3], d: true};
187214
var thirdErr = new BaseError(thirdMeta, secondErr, '%s is %s', 'something', 'wrong');
188-
thirdErr.message.should.equal('something is wrong && the second error && the first error');
215+
var targetMessage = 'something is wrong && the second error && the first error';
216+
217+
thirdErr.message.should.equal(targetMessage);
189218
thirdErr.meta.should.deepEqual({a: 1, b: '2', c: [3], d: true});
190219
thirdErr.stack.should.be.a.String();
220+
thirdErr.stack.indexOf('BaseError: ' + targetMessage).should.equal(0);
191221
thirdErr.stack.match(/\==== Pre-Error-Stack ====/g).length.should.equal(2);
192222
});
223+
224+
it('show pre error message if current error without any message', function() {
225+
var firstErr = new Error('the first error');
226+
var secondMeta = {a: 1, b: 3};
227+
var secondErr = new BaseError(firstErr, secondMeta);
228+
var targetMessage = 'the first error';
229+
230+
secondErr.message.should.equal(targetMessage);
231+
secondErr.stack.should.be.a.String();
232+
secondErr.stack.indexOf('BaseError: ' + targetMessage).should.equal(0);
233+
});
193234
});
194235
});

0 commit comments

Comments
 (0)