fix(fakeAsync): have fakeAsync use Proxy zone. (#10797)

Closes #10503

It is possible for code in `beforeEach` to capture and fork a zone
(for example creating `NgZone` in `beforeEach`). Subsequently the code
in `it` may chose to do `fakeAsync`. The issue is that because the
code in `it` can use `NgZone` from the `beforeEach`. it effectively can
escape the `fakeAsync` zone. A solution is to run all of the test in
`ProxyZone` which allows a test to dynamically replace the rules at any
time. This allows the `beforeEach` to fork a zone, and then `it` to
retroactively became `fakeAsync` zone.
This commit is contained in:
Miško Hevery
2016-08-19 12:10:53 -07:00
committed by Kara
parent 477e425f57
commit 8a5eb08672
16 changed files with 178 additions and 45 deletions

View File

@ -6,11 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/
import {BaseException} from '@angular/core';
import {NgZone} from '@angular/core/src/zone/ng_zone';
import {async, fakeAsync, flushMicrotasks} from '@angular/core/testing';
import {AsyncTestCompleter, Log, beforeEach, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {BaseException} from '../../src/facade/exceptions';
import {isPresent, scheduleMicroTask} from '../../src/facade/lang';
var needsLongerTimers = browserDetection.isSlow || browserDetection.isEdge;
@ -753,4 +754,44 @@ function commonTests() {
}, resultTimer);
}), testTimeout);
});
describe('bugs', () => {
describe('#10503', () => {
let ngZone: NgZone;
beforeEach(inject([NgZone], (_ngZone: NgZone) => {
// Create a zone outside the fakeAsync.
ngZone = _ngZone;
}));
it('should fakeAsync even if the NgZone was created outside.', fakeAsync(() => {
let result: string = null;
// try to escape the current fakeAsync zone by using NgZone which was created outside.
ngZone.run(() => {
Promise.resolve('works').then((v) => result = v);
flushMicrotasks();
});
expect(result).toEqual('works');
}));
describe('async', () => {
let asyncResult: string;
const waitLongerThenTestFrameworkAsyncTimeout = 5;
beforeEach(() => { asyncResult = null; });
it('should async even if the NgZone was created outside.', async(() => {
// try to escape the current async zone by using NgZone which was created outside.
ngZone.run(() => {
setTimeout(() => {
Promise.resolve('works').then((v) => asyncResult = v);
}, waitLongerThenTestFrameworkAsyncTimeout);
});
}));
afterEach(() => { expect(asyncResult).toEqual('works'); });
});
});
});
}