diff --git a/lib/reporters/base.js b/lib/reporters/base.js index 4c9e8064cd..cedc67a29d 100644 --- a/lib/reporters/base.js +++ b/lib/reporters/base.js @@ -151,6 +151,28 @@ exports.cursor = { } }; +/** + * This function dumps long stack traces for exceptions having a cause() + * method. The error classes from + * [verror](https://github.com/davepacheco/node-verror) and + * [restify v2.0](https://github.com/mcavage/node-restify) are examples. + * + * @param {Error} ex + * @return {string} + * @api public + */ + +exports.getFullErrorStack = function(err, message) { + var ret = err.stack || message || ''; + if (err.cause && typeof (err.cause) === 'function') { + var causeErr = err.cause(); + if (causeErr) { + ret += '\n' + ' ' + 'Caused by: ' + exports.getFullErrorStack(causeErr); + } + } + return ret; +}; + /** * Outut the given `failures` as a list. * @@ -177,7 +199,7 @@ exports.list = function(failures) { } else { message = ''; } - var stack = err.stack || message; + var stack = exports.getFullErrorStack(err, message); var index = message ? stack.indexOf(message) : -1; var actual = err.actual; var expected = err.expected; diff --git a/lib/runner.js b/lib/runner.js index 86bd4dc4af..3c3984146e 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -226,9 +226,15 @@ Runner.prototype.fail = function(test, err) { err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)'); } - err.stack = (this.fullStackTrace || !err.stack) - ? err.stack - : stackFilter(err.stack); + var causeErr = err; + + while (causeErr) { + causeErr.stack = (this.fullStackTrace || !causeErr.stack) + ? causeErr.stack + : stackFilter(causeErr.stack); + + causeErr = causeErr.cause && typeof (causeErr.cause) === 'function' ? causeErr.cause() : false; + } this.emit('fail', test, err); }; diff --git a/test/reporters/base.js b/test/reporters/base.js index bbd0d3a9a7..3eb861d21d 100644 --- a/test/reporters/base.js +++ b/test/reporters/base.js @@ -197,6 +197,21 @@ describe('Base reporter', function () { errOut.should.equal('1) test title:\n an error happened'); }); + it('should append the cause() property to stack trace when set', function () { + var err = { + message: 'Error', + stack: 'Error\nfoo\nbar', + showDiff: false, + cause: function() { return { stack: 'Cause Stack' }; } + }; + var test = makeTest(err); + + Base.list([test]); + + var errOut = stdout.join('\n').trim(); + errOut.should.equal('1) test title:\n Error\n foo\n bar\n Caused by: Cause Stack'); + }); + it('should not modify stack if it does not contain message', function () { var err = { message: 'Error',