From 2bd748218c59a05e648c14b8e8f795367bdea0c9 Mon Sep 17 00:00:00 2001 From: "JiaLi.Passion" Date: Sun, 19 Nov 2017 00:45:59 +0900 Subject: [PATCH 1/2] feat(promise): fix #955, print readable log when uncaught promise error --- lib/common/promise.ts | 12 +++++++++++- test/common/Promise.spec.ts | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/lib/common/promise.ts b/lib/common/promise.ts index f2d4e6c98..f2df7767c 100644 --- a/lib/common/promise.ts +++ b/lib/common/promise.ts @@ -6,6 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePrivate) => { + function readableObjectToString(obj: any) { + if (obj && obj.toString === Object.prototype.toString) { + const className = obj.constructor && obj.constructor.name; + return (className ? className : '') + ': ' + JSON.stringify(obj); + } + + return obj ? obj.toString() : Object.prototype.toString.call(obj); + } + interface UncaughtPromiseError extends Error { zone: AmbientZone; task: Task; @@ -164,8 +173,9 @@ 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): ' + value + + 'Uncaught (in promise): ' + readableObjectToString(value) + (value && value.stack ? '\n' + value.stack : '')); } catch (err) { const error: UncaughtPromiseError = err; diff --git a/test/common/Promise.spec.ts b/test/common/Promise.spec.ts index 00c4db71f..eb66cff0e 100644 --- a/test/common/Promise.spec.ts +++ b/test/common/Promise.spec.ts @@ -33,6 +33,11 @@ function flushMicrotasks() { Zone.current.get('flush')(); } +class TestRejection { + prop1: string; + prop2: string; +} + describe( 'Promise', ifEnvSupports('Promise', function() { if (!global.Promise) return; @@ -344,6 +349,38 @@ describe( done(); }); }); + + it('should print readable information when throw a not error object', (done) => { + let promiseError: Error = null; + let zone: Zone = null; + let task: Task = 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'; + Promise.reject(rejectObj); + expect(promiseError).toBe(null); + }); + setTimeout((): void => null); + setTimeout(() => { + expect(promiseError.message) + .toEqual('Uncaught (in promise): TestRejection: ' + JSON.stringify(rejectObj)); + done(); + }); + }); }); describe('Promise.race', () => { From 24c8811a010e513740ca1bfbe2f26e0f52377431 Mon Sep 17 00:00:00 2001 From: "JiaLi.Passion" Date: Tue, 19 Dec 2017 15:14:51 +0900 Subject: [PATCH 2/2] fix(promise): handle test case error in IE --- test/common/Promise.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/Promise.spec.ts b/test/common/Promise.spec.ts index eb66cff0e..6f2ea565f 100644 --- a/test/common/Promise.spec.ts +++ b/test/common/Promise.spec.ts @@ -377,7 +377,7 @@ describe( setTimeout((): void => null); setTimeout(() => { expect(promiseError.message) - .toEqual('Uncaught (in promise): TestRejection: ' + JSON.stringify(rejectObj)); + .toMatch(/Uncaught \(in promise\):.*: {"prop1":"value1","prop2":"value2"}/); done(); }); });