fix(fake_async): share zone between beforeEach
and it
This is needed for the case if a `beforeEach` instantiates `NgZone`and the `it` uses `TestComponentBuilder.createFakeAsync`. Otherwise the `NgZone` will use the root zone as parent, and `TestComponentBuilder.createFakeAsync` will always return undefined as `tick` does not forward promises created under the zone of `NgZone`.
This commit is contained in:
parent
3ce11ed58c
commit
16cc9b46aa
@ -285,5 +285,21 @@ export function main() {
|
||||
}).toThrowError('The code should be running in the fakeAsync zone to call this function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('only one `fakeAsync` zone per test', () => {
|
||||
let zoneInBeforeEach: Zone;
|
||||
let zoneInTest1: Zone;
|
||||
beforeEach(fakeAsync(() => { zoneInBeforeEach = Zone.current; }));
|
||||
|
||||
it('should use the same zone as in beforeEach', fakeAsync(() => {
|
||||
zoneInTest1 = Zone.current;
|
||||
expect(zoneInTest1).toBe(zoneInBeforeEach);
|
||||
}));
|
||||
|
||||
it('should use a different zone between tests', fakeAsync(() => {
|
||||
expect(Zone.current).toBe(zoneInBeforeEach);
|
||||
expect(Zone.current).not.toBe(zoneInTest1);
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -10,6 +10,22 @@ import {BaseException} from '../index';
|
||||
|
||||
let _FakeAsyncTestZoneSpecType = (Zone as any /** TODO #9100 */)['FakeAsyncTestZoneSpec'];
|
||||
|
||||
let _fakeAsyncZone: Zone = null;
|
||||
let _fakeAsyncTestZoneSpec: any = null;
|
||||
|
||||
/**
|
||||
* Clears out the shared fake async zone for a test.
|
||||
* To be called in a global `beforeEach`.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
export function resetFakeAsyncZone() {
|
||||
_fakeAsyncZone = null;
|
||||
_fakeAsyncTestZoneSpec = null;
|
||||
}
|
||||
|
||||
let _inFakeAsyncCall = false;
|
||||
|
||||
/**
|
||||
* Wraps a function to be executed in the fakeAsync zone:
|
||||
* - microtasks are manually executed by calling `flushMicrotasks()`,
|
||||
@ -29,40 +45,49 @@ let _FakeAsyncTestZoneSpecType = (Zone as any /** TODO #9100 */)['FakeAsyncTestZ
|
||||
* @experimental
|
||||
*/
|
||||
export function fakeAsync(fn: Function): (...args: any[]) => any {
|
||||
if (Zone.current.get('FakeAsyncTestZoneSpec') != null) {
|
||||
throw new BaseException('fakeAsync() calls can not be nested');
|
||||
}
|
||||
|
||||
let fakeAsyncTestZoneSpec = new _FakeAsyncTestZoneSpecType();
|
||||
let fakeAsyncZone = Zone.current.fork(fakeAsyncTestZoneSpec);
|
||||
|
||||
return function(...args: any[] /** TODO #9100 */) {
|
||||
let res = fakeAsyncZone.run(() => {
|
||||
let res = fn(...args);
|
||||
flushMicrotasks();
|
||||
if (_inFakeAsyncCall) {
|
||||
throw new BaseException('fakeAsync() calls can not be nested');
|
||||
}
|
||||
_inFakeAsyncCall = true;
|
||||
try {
|
||||
if (!_fakeAsyncZone) {
|
||||
if (Zone.current.get('FakeAsyncTestZoneSpec') != null) {
|
||||
throw new BaseException('fakeAsync() calls can not be nested');
|
||||
}
|
||||
|
||||
_fakeAsyncTestZoneSpec = new _FakeAsyncTestZoneSpecType();
|
||||
_fakeAsyncZone = Zone.current.fork(_fakeAsyncTestZoneSpec);
|
||||
}
|
||||
|
||||
let res = _fakeAsyncZone.run(() => {
|
||||
let res = fn(...args);
|
||||
flushMicrotasks();
|
||||
return res;
|
||||
});
|
||||
|
||||
if (_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length > 0) {
|
||||
throw new BaseException(
|
||||
`${_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length} ` +
|
||||
`periodic timer(s) still in the queue.`);
|
||||
}
|
||||
|
||||
if (_fakeAsyncTestZoneSpec.pendingTimers.length > 0) {
|
||||
throw new BaseException(
|
||||
`${_fakeAsyncTestZoneSpec.pendingTimers.length} timer(s) still in the queue.`);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
|
||||
if (fakeAsyncTestZoneSpec.pendingPeriodicTimers.length > 0) {
|
||||
throw new BaseException(
|
||||
`${fakeAsyncTestZoneSpec.pendingPeriodicTimers.length} ` +
|
||||
`periodic timer(s) still in the queue.`);
|
||||
} finally {
|
||||
_inFakeAsyncCall = false;
|
||||
}
|
||||
|
||||
if (fakeAsyncTestZoneSpec.pendingTimers.length > 0) {
|
||||
throw new BaseException(
|
||||
`${fakeAsyncTestZoneSpec.pendingTimers.length} timer(s) still in the queue.`);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
function _getFakeAsyncZoneSpec(): any {
|
||||
let zoneSpec = Zone.current.get('FakeAsyncTestZoneSpec');
|
||||
if (zoneSpec == null) {
|
||||
if (_fakeAsyncTestZoneSpec == null) {
|
||||
throw new Error('The code should be running in the fakeAsync zone to call this function');
|
||||
}
|
||||
return zoneSpec;
|
||||
return _fakeAsyncTestZoneSpec;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,15 +14,19 @@
|
||||
|
||||
import {SchemaMetadata} from '../index';
|
||||
|
||||
import {resetFakeAsyncZone} from './fake_async';
|
||||
import {TestBed, TestModuleMetadata, getTestBed} from './test_bed';
|
||||
|
||||
declare var global: any;
|
||||
|
||||
var _global = <any>(typeof window === 'undefined' ? global : window);
|
||||
|
||||
// Reset the test providers before each test.
|
||||
// Reset the test providers and the fake async zone before each test.
|
||||
if (_global.beforeEach) {
|
||||
_global.beforeEach(() => { TestBed.resetTestingModule(); });
|
||||
_global.beforeEach(() => {
|
||||
TestBed.resetTestingModule();
|
||||
resetFakeAsyncZone();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user