Skip to content

Commit 99d679d

Browse files
atscottthePunderWoman
authored andcommitted
feat(zone.js): Add 'flush' parameter option to fakeAsync to flush after the test (#57137)
From the internal issue on the matter: > When using the standard Jasmine version of it promises returned by the body function are automatically awaited. The Catalyst version of it is fake-async, so awaiting the promise does not make sense; however it would be nice if Catalyst automatically flushed the promise to replicate the experience of using standard it. This would allow users to do the following: ``` it('should fail later', async () => { await new Promise(r => setTimeout(r)); fail('failure'); }); ``` > In Catalyst today the above test will pass. If this proposal to automatically flush the resulting promise were implemented it would fail. Flushing after the tests complete has been the default behavior inside Google since 2020. Very few tests remain that use the old behavior of only flushing microtasks. The example above would actually fail with `fakeAsync` due to the pending timer, but the argument still remains the same. We might as well just flush if we're going to fail the test anyways by throwing if there's no flush at the end. PR Close #57137
1 parent 827070e commit 99d679d

1 file changed

Lines changed: 25 additions & 15 deletions

File tree

packages/zone.js/lib/zone-spec/fake-async-test.ts

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,7 @@ class FakeAsyncTestZoneSpec implements ZoneSpec {
785785
}
786786
}
787787

788-
let _fakeAsyncTestZoneSpec: any = null;
788+
let _fakeAsyncTestZoneSpec: FakeAsyncTestZoneSpec | null = null;
789789

790790
type ProxyZoneSpecType = {
791791
setDelegate(delegateSpec: ZoneSpec): void;
@@ -816,7 +816,8 @@ export function resetFakeAsyncZone() {
816816
* - microtasks are manually executed by calling `flushMicrotasks()`,
817817
* - timers are synchronous, `tick()` simulates the asynchronous passage of time.
818818
*
819-
* If there are any pending timers at the end of the function, an exception will be thrown.
819+
* When flush is `false`, if there are any pending timers at the end of the function,
820+
* an exception will be thrown.
820821
*
821822
* Can be used to wrap inject() calls.
822823
*
@@ -825,11 +826,14 @@ export function resetFakeAsyncZone() {
825826
* {@example core/testing/ts/fake_async.ts region='basic'}
826827
*
827828
* @param fn
829+
* @param options
830+
* flush: when true, will drain the macrotask queue after the test function completes.
828831
* @returns The function wrapped to be executed in the fakeAsync zone
829832
*
830833
* @experimental
831834
*/
832-
export function fakeAsync(fn: Function): (...args: any[]) => any {
835+
export function fakeAsync(fn: Function, options: {flush?: boolean} = {}): (...args: any[]) => any {
836+
const {flush = false} = options;
833837
// Not using an arrow function to preserve context passed from call site
834838
const fakeAsyncFn: any = function (this: unknown, ...args: any[]) {
835839
const ProxyZoneSpec = getProxyZoneSpec();
@@ -851,7 +855,7 @@ export function fakeAsync(fn: Function): (...args: any[]) => any {
851855
throw new Error('fakeAsync() calls can not be nested');
852856
}
853857

854-
_fakeAsyncTestZoneSpec = new FakeAsyncTestZoneSpec();
858+
_fakeAsyncTestZoneSpec = new FakeAsyncTestZoneSpec() as FakeAsyncTestZoneSpec;
855859
}
856860

857861
let res: any;
@@ -860,22 +864,28 @@ export function fakeAsync(fn: Function): (...args: any[]) => any {
860864
_fakeAsyncTestZoneSpec.lockDatePatch();
861865
try {
862866
res = fn.apply(this, args);
863-
flushMicrotasks();
867+
if (flush) {
868+
_fakeAsyncTestZoneSpec.flush(20, true);
869+
} else {
870+
flushMicrotasks();
871+
}
864872
} finally {
865873
proxyZoneSpec.setDelegate(lastProxyZoneSpec);
866874
}
867875

868-
if (_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length > 0) {
869-
throw new Error(
870-
`${_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length} ` +
871-
`periodic timer(s) still in the queue.`,
872-
);
873-
}
876+
if (!flush) {
877+
if (_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length > 0) {
878+
throw new Error(
879+
`${_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length} ` +
880+
`periodic timer(s) still in the queue.`,
881+
);
882+
}
874883

875-
if (_fakeAsyncTestZoneSpec.pendingTimers.length > 0) {
876-
throw new Error(
877-
`${_fakeAsyncTestZoneSpec.pendingTimers.length} timer(s) still in the queue.`,
878-
);
884+
if (_fakeAsyncTestZoneSpec.pendingTimers.length > 0) {
885+
throw new Error(
886+
`${_fakeAsyncTestZoneSpec.pendingTimers.length} timer(s) still in the queue.`,
887+
);
888+
}
879889
}
880890
return res;
881891
} finally {

0 commit comments

Comments
 (0)