From 2bb9a6535115ad8ba3c56781a4fe4141936cefe6 Mon Sep 17 00:00:00 2001 From: JiaLiPassion Date: Sun, 7 Jul 2019 11:07:32 +0800 Subject: [PATCH] fix(zone.js): don't wrap uncaught promise error. (#31443) Close #27840 PR Close #31443 --- packages/zone.js/lib/common/promise.ts | 31 ++++++++------- packages/zone.js/test/common/Promise.spec.ts | 38 +++++++++++++++++-- .../test/zone-spec/fake-async-test.spec.ts | 6 +-- 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/packages/zone.js/lib/common/promise.ts b/packages/zone.js/lib/common/promise.ts index 1faae6effc..cc5f401e90 100644 --- a/packages/zone.js/lib/common/promise.ts +++ b/packages/zone.js/lib/common/promise.ts @@ -176,20 +176,25 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr } if (queue.length == 0 && state == REJECTED) { (promise as any)[symbolState] = REJECTED_NO_CATCH; - try { - // try to print more readable error log - throw new Error( - 'Uncaught (in promise): ' + readableObjectToString(value) + - (value && value.stack ? '\n' + value.stack : '')); - } catch (err) { - const error: UncaughtPromiseError = err; - error.rejection = value; - error.promise = promise; - error.zone = Zone.current; - error.task = Zone.currentTask !; - _uncaughtPromiseErrors.push(error); - api.scheduleMicroTask(); // to make sure that it is running + let uncaughtPromiseError: any; + if (value instanceof Error || (value && value.message)) { + uncaughtPromiseError = value; + } else { + try { + // try to print more readable error log + throw new Error( + 'Uncaught (in promise): ' + readableObjectToString(value) + + (value && value.stack ? '\n' + value.stack : '')); + } catch (err) { + uncaughtPromiseError = err; + } } + uncaughtPromiseError.rejection = value; + uncaughtPromiseError.promise = promise; + uncaughtPromiseError.zone = Zone.current; + uncaughtPromiseError.task = Zone.currentTask !; + _uncaughtPromiseErrors.push(uncaughtPromiseError); + api.scheduleMicroTask(); // to make sure that it is running } } } diff --git a/packages/zone.js/test/common/Promise.spec.ts b/packages/zone.js/test/common/Promise.spec.ts index 7165b184be..6f0f3e2da4 100644 --- a/packages/zone.js/test/common/Promise.spec.ts +++ b/packages/zone.js/test/common/Promise.spec.ts @@ -345,11 +345,8 @@ describe( }); setTimeout((): any => null); setTimeout(() => { - expect(promiseError !.message) - .toBe( - 'Uncaught (in promise): ' + error + - (error !.stack ? '\n' + error !.stack : '')); expect((promiseError as any)['rejection']).toBe(error); + expect(promiseError).toBe(error); expect((promiseError as any)['zone']).toBe(zone); expect((promiseError as any)['task']).toBe(task); done(); @@ -389,6 +386,39 @@ describe( }); }); + it('should print original information when throw a not error object with a message property', + (done) => { + let promiseError: Error|null = null; + let zone: Zone|null = null; + let task: Task|null = null; + let rejectObj: TestRejection; + queueZone + .fork({ + name: 'promise-error', + onHandleError: (delegate: ZoneDelegate, current: Zone, target: Zone, error: any): + boolean => { + promiseError = error; + delegate.handleError(target, error); + return false; + } + }) + .run(() => { + zone = Zone.current; + task = Zone.currentTask; + rejectObj = new TestRejection(); + rejectObj.prop1 = 'value1'; + rejectObj.prop2 = 'value2'; + (rejectObj as any).message = 'rejectMessage'; + Promise.reject(rejectObj); + expect(promiseError).toBe(null); + }); + setTimeout((): any => null); + setTimeout(() => { + expect(promiseError).toEqual(rejectObj as any); + done(); + }); + }); + describe('Promise.race', () => { it('should reject the value', () => { queueZone.run(() => { diff --git a/packages/zone.js/test/zone-spec/fake-async-test.spec.ts b/packages/zone.js/test/zone-spec/fake-async-test.spec.ts index f538f6af88..ce642bd4dd 100644 --- a/packages/zone.js/test/zone-spec/fake-async-test.spec.ts +++ b/packages/zone.js/test/zone-spec/fake-async-test.spec.ts @@ -84,9 +84,7 @@ describe('FakeAsyncTestZoneSpec', () => { () => { fakeAsyncTestZone.run(() => { Promise.resolve(null).then((_) => { throw new Error('async'); }); - expect(() => { - testZoneSpec.flushMicrotasks(); - }).toThrowError(/Uncaught \(in promise\): Error: async/); + expect(() => { testZoneSpec.flushMicrotasks(); }).toThrowError(/async/); }); }); @@ -1171,7 +1169,7 @@ const {fakeAsync, tick, discardPeriodicTasks, flush, flushMicrotasks} = fakeAsyn resolvedPromise.then((_) => { throw new Error('async'); }); flushMicrotasks(); })(); - }).toThrowError(/Uncaught \(in promise\): Error: async/); + }).toThrowError(/async/); }); it('should complain if a test throws an exception', () => {