diff --git a/index.js b/index.js index eade8da..5cb6a73 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,7 @@ const indentString = require('indent-string'); const cleanStack = require('clean-stack'); const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); +const isString = value => typeof value === 'string' || value instanceof String; class AggregateError extends Error { constructor(errors) { @@ -23,7 +24,14 @@ class AggregateError extends Error { return new Error(error); }); - let message = errors.map(error => cleanInternalStack(cleanStack(error.stack))).join('\n'); + let message = errors + .map(error => { + // Unfortunately stack is not standardized as a property of Error instances + // which makes it necessary to explicitly check for it and its type. + // In case the stack property is missing the stringified error should be used instead. + return isString(error.stack) ? cleanInternalStack(cleanStack(error.stack)) : String(error); + }) + .join('\n'); message = '\n' + indentString(message, 4); super(message); diff --git a/test.js b/test.js index b5b3bb8..585e75c 100644 --- a/test.js +++ b/test.js @@ -26,3 +26,28 @@ test('main', t => { Object.assign(new Error(), {code: 'EQUX'}) ]); }); + +test('gracefully handle Error instances without a stack', t => { + class StacklessError extends Error { + constructor(...args) { + super(...args); + this.name = this.constructor.name; + delete this.stack; + } + } + + const error = new AggregateError([ + new Error('foo'), + new StacklessError('stackless') + ]); + + console.log(error); + + t.regex(error.message, /Error: foo\n {8}at /); + t.regex(error.message, /StacklessError: stackless/); + + t.deepEqual([...error], [ + new Error('foo'), + new StacklessError('stackless') + ]); +});