From 2cf5c4020339501537b1be8fbbffeae08453cfbc Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 1 Feb 2022 10:46:01 +0100 Subject: [PATCH] fix(zone.js): only call jasmine test done function once Currently zone.js may end up attempting to call the `done` function of async tests more than once. This used to be a noop, but Jasmine now logs the following warning: ``` An asynchronous function called its 'done' callback more than once. This is a bug in the spec, beforeAll, beforeEach, afterAll, or afterEach function in question. This will be treated as an error in a future version. See for more information ``` These changes add a wrapper around the `done` function so it only gets called once, otherwise we risk triggering errors in future versions of Jasmine. --- packages/zone.js/lib/jasmine/jasmine.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/zone.js/lib/jasmine/jasmine.ts b/packages/zone.js/lib/jasmine/jasmine.ts index cbdd2f8d3722..b16fc0fab4b8 100644 --- a/packages/zone.js/lib/jasmine/jasmine.ts +++ b/packages/zone.js/lib/jasmine/jasmine.ts @@ -192,9 +192,7 @@ Zone.__load_patch('jasmine', (global: any, Zone: ZoneType, api: _ZonePrivate) => function runInTestZone( testBody: Function, applyThis: any, queueRunner: QueueRunner, done?: Function) { const isClockInstalled = !!(jasmine as any)[symbol('clockInstalled')]; - const testProxyZoneSpec = queueRunner.testProxyZoneSpec!; const testProxyZone = queueRunner.testProxyZone!; - let lastDelegate; if (isClockInstalled && enableAutoFakeAsyncWhenClockPatched) { // auto run a fakeAsync const fakeAsyncModule = (Zone as any)[Zone.__symbol__('fakeAsyncTest')]; @@ -203,7 +201,9 @@ Zone.__load_patch('jasmine', (global: any, Zone: ZoneType, api: _ZonePrivate) => } } if (done) { - return testProxyZone.run(testBody, applyThis, [done]); + // `done` should only be called once, otherwise Jasmine will log a + // deprecation warning which will eventually turn into an error. + return testProxyZone.run(testBody, applyThis, [callOnce(done)]); } else { return testProxyZone.run(testBody, applyThis); } @@ -343,4 +343,18 @@ Zone.__load_patch('jasmine', (global: any, Zone: ZoneType, api: _ZonePrivate) => }; return ZoneQueueRunner; })(QueueRunner); + + /** Wraps a function so it is only invoked once. */ + function callOnce(fn: Function) { + let wasCalled = false; + let returnValue: unknown; + + return function(this: unknown) { + if (!wasCalled) { + wasCalled = true; + returnValue = fn.apply(this, arguments); + } + return returnValue; + } + } });