diff --git a/lib/zone-spec/long-stack-trace.ts b/lib/zone-spec/long-stack-trace.ts index dcbbfa06e..b9e25cfcb 100644 --- a/lib/zone-spec/long-stack-trace.ts +++ b/lib/zone-spec/long-stack-trace.ts @@ -27,18 +27,18 @@ function getStacktraceWithUncaughtError(): Error { function getStacktraceWithCaughtError(): Error { try { throw getStacktraceWithUncaughtError(); - } catch (error) { - return error; + } catch (err) { + return err; } } // Some implementations of exception handling don't create a stack trace if the exception // isn't thrown, however it's faster not to actually throw the exception. const error = getStacktraceWithUncaughtError(); -const coughtError = getStacktraceWithCaughtError(); +const caughtError = getStacktraceWithCaughtError(); const getStacktrace = error.stack ? getStacktraceWithUncaughtError : - (coughtError.stack ? getStacktraceWithCaughtError : getStacktraceWithUncaughtError); + (caughtError.stack ? getStacktraceWithCaughtError : getStacktraceWithUncaughtError); function getFrames(error: Error): string[] { return error.stack ? error.stack.split(NEWLINE) : []; @@ -77,6 +77,19 @@ function renderLongStackTrace(frames: LongStackTrace[], stack: string): string { Zone['longStackTraceZoneSpec'] = { name: 'long-stack-trace', longStackTraceLimit: 10, // Max number of task to keep the stack trace for. + // add a getLongStackTrace method in spec to + // handle handled reject promise error. + getLongStackTrace: function(error: Error): string { + if (!error) { + return undefined; + } + const task = error[Zone['__symbol__']('currentTask')]; + const trace = task && task.data && task.data[creationTrace]; + if (!trace) { + return error.stack; + } + return renderLongStackTrace(trace, error.stack); + }, onScheduleTask: function( parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task): any { diff --git a/lib/zone.ts b/lib/zone.ts index 225cc0b55..ca85fd601 100644 --- a/lib/zone.ts +++ b/lib/zone.ts @@ -1332,6 +1332,12 @@ const Zone: ZoneType = (function(global: any) { const queue = promise[symbolValue]; promise[symbolValue] = value; + // record task information in value when error occurs, so we can + // do some additional work such as render longStackTrace + if (state === REJECTED && value instanceof Error) { + value[__symbol__('currentTask')] = Zone.currentTask; + } + for (let i = 0; i < queue.length;) { scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); } diff --git a/test/zone-spec/long-stack-trace-zone.spec.ts b/test/zone-spec/long-stack-trace-zone.spec.ts index cebd673ce..d2c5932f6 100644 --- a/test/zone-spec/long-stack-trace-zone.spec.ts +++ b/test/zone-spec/long-stack-trace-zone.spec.ts @@ -12,9 +12,10 @@ const defineProperty = Object[zoneSymbol('defineProperty')] || Object.defineProp describe('longStackTraceZone', function() { let log: Error[]; let lstz: Zone; + let longStackTraceZoneSpec = Zone['longStackTraceZoneSpec']; beforeEach(function() { - lstz = Zone.current.fork(Zone['longStackTraceZoneSpec']).fork({ + lstz = Zone.current.fork(longStackTraceZoneSpec).fork({ name: 'long-stack-trace-zone-test', onHandleError: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, error: any): boolean => { @@ -67,7 +68,7 @@ describe('longStackTraceZone', function() { }); }); - it('should produce long stack traces when reject in promise', function(done) { + it('should produce long stack traces when has uncaught error in promise', function(done) { lstz.runGuarded(function() { setTimeout(function() { setTimeout(function() { @@ -91,6 +92,26 @@ describe('longStackTraceZone', function() { }, 0); }); }); + + it('should produce long stack traces when handling error in promise', function(done) { + lstz.runGuarded(function() { + setTimeout(function() { + setTimeout(function() { + let promise = new Promise(function(resolve, reject) { + setTimeout(function() { + reject(new Error('Hello Promise')); + }, 0); + }); + promise.catch(function(error) { + // should be able to get long stack trace + const longStackFrames: string = longStackTraceZoneSpec.getLongStackTrace(error); + expect(longStackFrames.split('Elapsed: ').length).toBe(4); + done(); + }); + }, 0); + }, 0); + }); + }); }); export let __something__;