angular/packages/core/testing/src/fake_async.ts
Miško Hevery b7a6f52d59 perf: latest tsickle to tree shake: abstract class methods & interfaces (#18236)
In previous version of tsickle abstract class methods were materialized.
The change resulted in 6Kb savings in angular.io bundle.

This change also required the removal of `@private` and `@return` type
annotation as it is explicitly dissalowed by tsickle.

NOTE: removed casts in front of `makeDecorator` due to:
https://github.com/angular/devkit/issues/45

```
 14938 Jul 19 13:16 0.b19e913fbdd6507d346b.chunk.js
  1535 Jul 19 13:16 inline.d8e019ea3cfdd86c2bd0.bundle.js
589178 Jul 19 13:16 main.54c97bcb6f254776b678.bundle.js
 34333 Jul 19 13:16 polyfills.4a3c9ca9481d53803157.bundle.js

 14938 Jul 18 16:55 0.b19e913fbdd6507d346b.chunk.js
  1535 Jul 18 16:55 inline.0c83abb44fad9a2768a7.bundle.js
582786 Jul 18 16:55 main.ea290db71b051813e156.bundle.js
 34333 Jul 18 16:55 polyfills.4a3c9ca9481d53803157.bundle.js

main savings: 589178 - 582786 = 6,392
```

PR Close #18236
2017-07-21 16:35:37 -05:00

151 lines
4.2 KiB
TypeScript

/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
const FakeAsyncTestZoneSpec = (Zone as any)['FakeAsyncTestZoneSpec'];
type ProxyZoneSpec = {
setDelegate(delegateSpec: ZoneSpec): void; getDelegate(): ZoneSpec; resetDelegate(): void;
};
const ProxyZoneSpec: {get(): ProxyZoneSpec; assertPresent: () => ProxyZoneSpec} =
(Zone as any)['ProxyZoneSpec'];
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() {
_fakeAsyncTestZoneSpec = null;
ProxyZoneSpec.assertPresent().resetDelegate();
}
let _inFakeAsyncCall = false;
/**
* Wraps a function to be executed in the fakeAsync zone:
* - microtasks are manually executed by calling `flushMicrotasks()`,
* - timers are synchronous, `tick()` simulates the asynchronous passage of time.
*
* If there are any pending timers at the end of the function, an exception will be thrown.
*
* Can be used to wrap inject() calls.
*
* ## Example
*
* {@example testing/ts/fake_async.ts region='basic'}
*
* @param fn
* @returns The function wrapped to be executed in the fakeAsync zone
*
* @experimental
*/
export function fakeAsync(fn: Function): (...args: any[]) => any {
// Not using an arrow function to preserve context passed from call site
return function(...args: any[]) {
const proxyZoneSpec = ProxyZoneSpec.assertPresent();
if (_inFakeAsyncCall) {
throw new Error('fakeAsync() calls can not be nested');
}
_inFakeAsyncCall = true;
try {
if (!_fakeAsyncTestZoneSpec) {
if (proxyZoneSpec.getDelegate() instanceof FakeAsyncTestZoneSpec) {
throw new Error('fakeAsync() calls can not be nested');
}
_fakeAsyncTestZoneSpec = new FakeAsyncTestZoneSpec();
}
let res: any;
const lastProxyZoneSpec = proxyZoneSpec.getDelegate();
proxyZoneSpec.setDelegate(_fakeAsyncTestZoneSpec);
try {
res = fn.apply(this, args);
flushMicrotasks();
} finally {
proxyZoneSpec.setDelegate(lastProxyZoneSpec);
}
if (_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length > 0) {
throw new Error(
`${_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length} ` +
`periodic timer(s) still in the queue.`);
}
if (_fakeAsyncTestZoneSpec.pendingTimers.length > 0) {
throw new Error(
`${_fakeAsyncTestZoneSpec.pendingTimers.length} timer(s) still in the queue.`);
}
return res;
} finally {
_inFakeAsyncCall = false;
resetFakeAsyncZone();
}
};
}
function _getFakeAsyncZoneSpec(): any {
if (_fakeAsyncTestZoneSpec == null) {
throw new Error('The code should be running in the fakeAsync zone to call this function');
}
return _fakeAsyncTestZoneSpec;
}
/**
* Simulates the asynchronous passage of time for the timers in the fakeAsync zone.
*
* The microtasks queue is drained at the very start of this function and after any timer callback
* has been executed.
*
* ## Example
*
* {@example testing/ts/fake_async.ts region='basic'}
*
* @experimental
*/
export function tick(millis: number = 0): void {
_getFakeAsyncZoneSpec().tick(millis);
}
/**
* Simulates the asynchronous passage of time for the timers in the fakeAsync zone by
* draining the macrotask queue until it is empty. The returned value is the milliseconds
* of time that would have been elapsed.
*
* @param maxTurns
* @returns The simulated time elapsed, in millis.
*
* @experimental
*/
export function flush(maxTurns?: number): number {
return _getFakeAsyncZoneSpec().flush(maxTurns);
}
/**
* Discard all remaining periodic tasks.
*
* @experimental
*/
export function discardPeriodicTasks(): void {
const zoneSpec = _getFakeAsyncZoneSpec();
const pendingTimers = zoneSpec.pendingPeriodicTimers;
zoneSpec.pendingPeriodicTimers.length = 0;
}
/**
* Flush any pending microtasks.
*
* @experimental
*/
export function flushMicrotasks(): void {
_getFakeAsyncZoneSpec().flushMicrotasks();
}