diff --git a/packages/core/src/testability/testability.ts b/packages/core/src/testability/testability.ts index f007707880..f39e0bb823 100644 --- a/packages/core/src/testability/testability.ts +++ b/packages/core/src/testability/testability.ts @@ -98,22 +98,13 @@ export class Testability implements PublicTestability { /** @internal */ _runCallbacksIfReady(): void { if (this.isStable()) { - if (this._callbacks.length !== 0) { - // Schedules the call backs after a macro task run outside of the angular zone to make sure - // no new task are added - this._ngZone.runOutsideAngular(() => { - setTimeout(() => { - if (this.isStable()) { - while (this._callbacks.length !== 0) { - (this._callbacks.pop() !)(this._didWork); - } - this._didWork = false; - } - }); - }); - } else { + // Schedules the call backs in a new frame so that it is always async. + scheduleMicroTask(() => { + while (this._callbacks.length !== 0) { + (this._callbacks.pop() !)(this._didWork); + } this._didWork = false; - } + }); } else { // Not Ready this._didWork = true; diff --git a/packages/core/test/testability/testability_spec.ts b/packages/core/test/testability/testability_spec.ts index ec5deb1af9..ee5e7560c5 100644 --- a/packages/core/test/testability/testability_spec.ts +++ b/packages/core/test/testability/testability_spec.ts @@ -16,11 +16,13 @@ import {scheduleMicroTask} from '../../src/util'; -// Schedules a task to be run after Testability checks for oustanding tasks. Since Testability -// uses a 0 second timeout to check for outstanding tasks we add our 0 second timeout after a -// micro task (which ensures Testability's timeout is run first). -function afterTestabilityCheck(fn: Function): void { - scheduleMicroTask(() => setTimeout(fn)); +// Schedules a microtasks (using a resolved promise .then()) +function microTask(fn: Function): void { + scheduleMicroTask(() => { + // We do double dispatch so that we can wait for scheduleMicrotask in the Testability when + // NgZone becomes stable. + scheduleMicroTask(fn); + }); } @Injectable() @@ -63,7 +65,7 @@ class MockNgZone extends NgZone { it('should fire whenstable callbacks if pending count is 0', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { testability.whenStable(execute); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).toHaveBeenCalled(); async.done(); }); @@ -80,11 +82,11 @@ class MockNgZone extends NgZone { testability.increasePendingRequestCount(); testability.whenStable(execute); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).not.toHaveBeenCalled(); testability.decreasePendingRequestCount(); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).not.toHaveBeenCalled(); async.done(); }); @@ -96,11 +98,11 @@ class MockNgZone extends NgZone { testability.increasePendingRequestCount(); testability.whenStable(execute); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).not.toHaveBeenCalled(); testability.decreasePendingRequestCount(); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).toHaveBeenCalled(); async.done(); }); @@ -118,7 +120,7 @@ class MockNgZone extends NgZone { it('should fire whenstable callbacks with didWork if pending count is 0', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { testability.whenStable(execute); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).toHaveBeenCalledWith(false); async.done(); }); @@ -129,14 +131,14 @@ class MockNgZone extends NgZone { testability.increasePendingRequestCount(); testability.whenStable(execute); - afterTestabilityCheck(() => { + microTask(() => { testability.decreasePendingRequestCount(); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).toHaveBeenCalledWith(true); testability.whenStable(execute2); - afterTestabilityCheck(() => { + microTask(() => { expect(execute2).toHaveBeenCalledWith(false); async.done(); }); @@ -152,7 +154,7 @@ class MockNgZone extends NgZone { ngZone.stable(); testability.whenStable(execute); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).toHaveBeenCalled(); async.done(); }); @@ -171,11 +173,11 @@ class MockNgZone extends NgZone { ngZone.unstable(); testability.whenStable(execute); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).not.toHaveBeenCalled(); ngZone.stable(); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).toHaveBeenCalled(); async.done(); }); @@ -196,15 +198,15 @@ class MockNgZone extends NgZone { testability.increasePendingRequestCount(); testability.whenStable(execute); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).not.toHaveBeenCalled(); testability.decreasePendingRequestCount(); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).not.toHaveBeenCalled(); ngZone.stable(); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).toHaveBeenCalled(); async.done(); }); @@ -219,19 +221,19 @@ class MockNgZone extends NgZone { testability.increasePendingRequestCount(); testability.whenStable(execute); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).not.toHaveBeenCalled(); ngZone.stable(); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).not.toHaveBeenCalled(); testability.decreasePendingRequestCount(); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).not.toHaveBeenCalled(); testability.decreasePendingRequestCount(); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).toHaveBeenCalled(); async.done(); }); @@ -246,11 +248,11 @@ class MockNgZone extends NgZone { ngZone.stable(); testability.whenStable(execute); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).toHaveBeenCalledWith(true); testability.whenStable(execute2); - afterTestabilityCheck(() => { + microTask(() => { expect(execute2).toHaveBeenCalledWith(false); async.done(); }); @@ -262,14 +264,14 @@ class MockNgZone extends NgZone { ngZone.unstable(); testability.whenStable(execute); - afterTestabilityCheck(() => { + microTask(() => { ngZone.stable(); - afterTestabilityCheck(() => { + microTask(() => { expect(execute).toHaveBeenCalledWith(true); testability.whenStable(execute2); - afterTestabilityCheck(() => { + microTask(() => { expect(execute2).toHaveBeenCalledWith(false); async.done(); });