Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit 40b110d

Browse files
JiaLiPassionmhevery
authored andcommitted
fix(proxy): proxyZone should call onHasTask when change delegate (#1030)
1 parent e1df4bc commit 40b110d

File tree

5 files changed

+333
-6
lines changed

5 files changed

+333
-6
lines changed

lib/jasmine/jasmine.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
? Object.create(b)
1919
: ((__.prototype = b.prototype), new (__ as any)());
2020
};
21+
const _global: any = typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global;
2122
// Patch jasmine's describe/it/beforeEach/afterEach functions so test code always runs
2223
// in a testZone (ProxyZone). (See: angular/zone.js#91 & angular/angular#10503)
2324
if (!Zone) throw new Error('Missing: zone.js');
@@ -202,13 +203,24 @@
202203
function ZoneQueueRunner(attrs: {
203204
onComplete: Function;
204205
userContext?: any;
206+
timeout?: { setTimeout: Function; clearTimeout: Function };
205207
}) {
206208
attrs.onComplete = (fn => () => {
207209
// All functions are done, clear the test zone.
208210
this.testProxyZone = null;
209211
this.testProxyZoneSpec = null;
210212
ambientZone.scheduleMicroTask('jasmine.onComplete', fn);
211213
})(attrs.onComplete);
214+
215+
const nativeSetTimeout = _global['__zone_symbol__setTimeout'];
216+
const nativeClearTimeout = _global['__zone_symbol__clearTimeout'];
217+
if (nativeSetTimeout) {
218+
// should run setTimeout inside jasmine outside of zone
219+
attrs.timeout = {
220+
setTimeout: nativeSetTimeout ? nativeSetTimeout : _global.setTimeout,
221+
clearTimeout: nativeClearTimeout ? nativeClearTimeout : _global.clearTimeout
222+
};
223+
}
212224
// create a userContext to hold the queueRunner itself
213225
// so we can access the testProxy in it/xit/beforeEach ...
214226
if ((jasmine as any).UserContext) {

lib/zone-spec/async-test.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class AsyncTestZoneSpec implements ZoneSpec {
1414
_pendingMicroTasks: boolean = false;
1515
_pendingMacroTasks: boolean = false;
1616
_alreadyErrored: boolean = false;
17+
_isSync: boolean = false;
1718
runZone = Zone.current;
1819
unresolvedChainedPromiseCount = 0;
1920

@@ -60,6 +61,9 @@ class AsyncTestZoneSpec implements ZoneSpec {
6061
properties: {[key: string]: any};
6162

6263
onScheduleTask(delegate: ZoneDelegate, current: Zone, target: Zone, task: Task): Task {
64+
if (task.type !== 'eventTask') {
65+
this._isSync = false;
66+
}
6367
if (task.type === 'microTask' && task.data && task.data instanceof Promise) {
6468
// check whether the promise is a chained promise
6569
if ((task.data as any)[AsyncTestZoneSpec.symbolParentUnresolved] === true) {
@@ -70,18 +74,39 @@ class AsyncTestZoneSpec implements ZoneSpec {
7074
return delegate.scheduleTask(target, task);
7175
}
7276

77+
onInvokeTask(delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, applyThis: any, applyArgs: any) {
78+
if (task.type !== 'eventTask') {
79+
this._isSync = false;
80+
}
81+
return delegate.invokeTask(target, task, applyThis, applyArgs);
82+
}
83+
84+
onCancelTask(delegate: ZoneDelegate, current: Zone, target: Zone, task: Task) {
85+
if (task.type !== 'eventTask') {
86+
this._isSync = false;
87+
}
88+
return delegate.cancelTask(target, task);
89+
}
90+
7391
// Note - we need to use onInvoke at the moment to call finish when a test is
7492
// fully synchronous. TODO(juliemr): remove this when the logic for
7593
// onHasTask changes and it calls whenever the task queues are dirty.
94+
// updated by(JiaLiPassion), only call finish callback when no task
95+
// was scheduled/invoked/canceled.
7696
onInvoke(
7797
parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, delegate: Function,
7898
applyThis: any, applyArgs: any[], source: string): any {
99+
let previousTaskCounts: any = null;
79100
try {
80101
this.patchPromiseForTest();
102+
this._isSync = true;
81103
return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source);
82104
} finally {
83105
this.unPatchPromiseForTest();
84-
this._finishCallbackIfDone();
106+
const afterTaskCounts: any = (parentZoneDelegate as any)._taskCounts;
107+
if (this._isSync) {
108+
this._finishCallbackIfDone();
109+
}
85110
}
86111
}
87112

lib/zone-spec/proxy.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ class ProxyZoneSpec implements ZoneSpec {
1414
properties: {[k: string]: any} = {'ProxyZoneSpec': this};
1515
propertyKeys: string[] = null;
1616

17+
lastTaskState: HasTaskState = null;
18+
isNeedToTriggerHasTask = false;
19+
1720
static get(): ProxyZoneSpec {
1821
return Zone.current.get('ProxyZoneSpec');
1922
}
@@ -35,13 +38,20 @@ class ProxyZoneSpec implements ZoneSpec {
3538

3639

3740
setDelegate(delegateSpec: ZoneSpec) {
41+
const isNewDelegate = this._delegateSpec !== delegateSpec;
3842
this._delegateSpec = delegateSpec;
3943
this.propertyKeys && this.propertyKeys.forEach((key) => delete this.properties[key]);
4044
this.propertyKeys = null;
4145
if (delegateSpec && delegateSpec.properties) {
4246
this.propertyKeys = Object.keys(delegateSpec.properties);
4347
this.propertyKeys.forEach((k) => this.properties[k] = delegateSpec.properties[k]);
4448
}
49+
// if set a new delegateSpec, shoulde check whether need to
50+
// trigger hasTask or not
51+
if (isNewDelegate && this.lastTaskState &&
52+
(this.lastTaskState.macroTask || this.lastTaskState.microTask)) {
53+
this.isNeedToTriggerHasTask = true;
54+
}
4555
}
4656

4757
getDelegate() {
@@ -53,6 +63,15 @@ class ProxyZoneSpec implements ZoneSpec {
5363
this.setDelegate(this.defaultSpecDelegate);
5464
}
5565

66+
tryTriggerHasTask(parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone) {
67+
if (this.isNeedToTriggerHasTask && this.lastTaskState) {
68+
// last delegateSpec has microTask or macroTask
69+
// should call onHasTask in current delegateSpec
70+
this.isNeedToTriggerHasTask = false;
71+
this.onHasTask(parentZoneDelegate, currentZone, targetZone, this.lastTaskState);
72+
}
73+
}
74+
5675

5776
onFork(parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, zoneSpec: ZoneSpec):
5877
Zone {
@@ -79,6 +98,7 @@ class ProxyZoneSpec implements ZoneSpec {
7998
onInvoke(
8099
parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, delegate: Function,
81100
applyThis: any, applyArgs: any[], source: string): any {
101+
this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone);
82102
if (this._delegateSpec && this._delegateSpec.onInvoke) {
83103
return this._delegateSpec.onInvoke(
84104
parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source);
@@ -108,7 +128,8 @@ class ProxyZoneSpec implements ZoneSpec {
108128
onInvokeTask(
109129
parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task,
110130
applyThis: any, applyArgs: any): any {
111-
if (this._delegateSpec && this._delegateSpec.onFork) {
131+
this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone);
132+
if (this._delegateSpec && this._delegateSpec.onInvokeTask) {
112133
return this._delegateSpec.onInvokeTask(
113134
parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs);
114135
} else {
@@ -118,6 +139,7 @@ class ProxyZoneSpec implements ZoneSpec {
118139

119140
onCancelTask(parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task):
120141
any {
142+
this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone);
121143
if (this._delegateSpec && this._delegateSpec.onCancelTask) {
122144
return this._delegateSpec.onCancelTask(parentZoneDelegate, currentZone, targetZone, task);
123145
} else {
@@ -126,6 +148,7 @@ class ProxyZoneSpec implements ZoneSpec {
126148
}
127149

128150
onHasTask(delegate: ZoneDelegate, current: Zone, target: Zone, hasTaskState: HasTaskState): void {
151+
this.lastTaskState = hasTaskState;
129152
if (this._delegateSpec && this._delegateSpec.onHasTask) {
130153
this._delegateSpec.onHasTask(delegate, current, target, hasTaskState);
131154
} else {

0 commit comments

Comments
 (0)