| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @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
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | (function(_global: any) { | 
					
						
							|  |  |  |   class AsyncTestZoneSpec implements ZoneSpec { | 
					
						
							|  |  |  |     static symbolParentUnresolved = Zone.__symbol__('parentUnresolved'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _pendingMicroTasks: boolean = false; | 
					
						
							|  |  |  |     _pendingMacroTasks: boolean = false; | 
					
						
							|  |  |  |     _alreadyErrored: boolean = false; | 
					
						
							|  |  |  |     _isSync: boolean = false; | 
					
						
							|  |  |  |     runZone = Zone.current; | 
					
						
							|  |  |  |     unresolvedChainedPromiseCount = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     supportWaitUnresolvedChainedPromise = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     constructor( | 
					
						
							|  |  |  |         private finishCallback: Function, private failCallback: Function, namePrefix: string) { | 
					
						
							|  |  |  |       this.name = 'asyncTestZone for ' + namePrefix; | 
					
						
							|  |  |  |       this.properties = {'AsyncTestZoneSpec': this}; | 
					
						
							|  |  |  |       this.supportWaitUnresolvedChainedPromise = | 
					
						
							|  |  |  |           _global[Zone.__symbol__('supportWaitUnResolvedChainedPromise')] === true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     isUnresolvedChainedPromisePending() { return this.unresolvedChainedPromiseCount > 0; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _finishCallbackIfDone() { | 
					
						
							|  |  |  |       if (!(this._pendingMicroTasks || this._pendingMacroTasks || | 
					
						
							|  |  |  |             (this.supportWaitUnresolvedChainedPromise && | 
					
						
							|  |  |  |              this.isUnresolvedChainedPromisePending()))) { | 
					
						
							|  |  |  |         // We do this because we would like to catch unhandled rejected promises.
 | 
					
						
							|  |  |  |         this.runZone.run(() => { | 
					
						
							|  |  |  |           setTimeout(() => { | 
					
						
							|  |  |  |             if (!this._alreadyErrored && !(this._pendingMicroTasks || this._pendingMacroTasks)) { | 
					
						
							|  |  |  |               this.finishCallback(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           }, 0); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     patchPromiseForTest() { | 
					
						
							|  |  |  |       if (!this.supportWaitUnresolvedChainedPromise) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       const patchPromiseForTest = (Promise as any)[Zone.__symbol__('patchPromiseForTest')]; | 
					
						
							|  |  |  |       if (patchPromiseForTest) { | 
					
						
							|  |  |  |         patchPromiseForTest(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     unPatchPromiseForTest() { | 
					
						
							|  |  |  |       if (!this.supportWaitUnresolvedChainedPromise) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       const unPatchPromiseForTest = (Promise as any)[Zone.__symbol__('unPatchPromiseForTest')]; | 
					
						
							|  |  |  |       if (unPatchPromiseForTest) { | 
					
						
							|  |  |  |         unPatchPromiseForTest(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // ZoneSpec implementation below.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     name: string; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     properties: {[key: string]: any}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     onScheduleTask(delegate: ZoneDelegate, current: Zone, target: Zone, task: Task): Task { | 
					
						
							|  |  |  |       if (task.type !== 'eventTask') { | 
					
						
							|  |  |  |         this._isSync = false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (task.type === 'microTask' && task.data && task.data instanceof Promise) { | 
					
						
							|  |  |  |         // check whether the promise is a chained promise
 | 
					
						
							|  |  |  |         if ((task.data as any)[AsyncTestZoneSpec.symbolParentUnresolved] === true) { | 
					
						
							|  |  |  |           // chained promise is being scheduled
 | 
					
						
							|  |  |  |           this.unresolvedChainedPromiseCount--; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return delegate.scheduleTask(target, task); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     onInvokeTask( | 
					
						
							|  |  |  |         delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, applyThis: any, | 
					
						
							|  |  |  |         applyArgs: any) { | 
					
						
							|  |  |  |       if (task.type !== 'eventTask') { | 
					
						
							|  |  |  |         this._isSync = false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return delegate.invokeTask(target, task, applyThis, applyArgs); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     onCancelTask(delegate: ZoneDelegate, current: Zone, target: Zone, task: Task) { | 
					
						
							|  |  |  |       if (task.type !== 'eventTask') { | 
					
						
							|  |  |  |         this._isSync = false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return delegate.cancelTask(target, task); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Note - we need to use onInvoke at the moment to call finish when a test is
 | 
					
						
							|  |  |  |     // fully synchronous. TODO(juliemr): remove this when the logic for
 | 
					
						
							|  |  |  |     // onHasTask changes and it calls whenever the task queues are dirty.
 | 
					
						
							|  |  |  |     // updated by(JiaLiPassion), only call finish callback when no task
 | 
					
						
							|  |  |  |     // was scheduled/invoked/canceled.
 | 
					
						
							|  |  |  |     onInvoke( | 
					
						
							|  |  |  |         parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, delegate: Function, | 
					
						
							|  |  |  |         applyThis: any, applyArgs?: any[], source?: string): any { | 
					
						
							|  |  |  |       let previousTaskCounts: any = null; | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         this._isSync = true; | 
					
						
							|  |  |  |         return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source); | 
					
						
							|  |  |  |       } finally { | 
					
						
							|  |  |  |         const afterTaskCounts: any = (parentZoneDelegate as any)._taskCounts; | 
					
						
							|  |  |  |         if (this._isSync) { | 
					
						
							|  |  |  |           this._finishCallbackIfDone(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     onHandleError( | 
					
						
							|  |  |  |         parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, | 
					
						
							|  |  |  |         error: any): boolean { | 
					
						
							|  |  |  |       // Let the parent try to handle the error.
 | 
					
						
							|  |  |  |       const result = parentZoneDelegate.handleError(targetZone, error); | 
					
						
							|  |  |  |       if (result) { | 
					
						
							|  |  |  |         this.failCallback(error); | 
					
						
							|  |  |  |         this._alreadyErrored = true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     onHasTask(delegate: ZoneDelegate, current: Zone, target: Zone, hasTaskState: HasTaskState) { | 
					
						
							|  |  |  |       delegate.hasTask(target, hasTaskState); | 
					
						
							|  |  |  |       if (hasTaskState.change == 'microTask') { | 
					
						
							|  |  |  |         this._pendingMicroTasks = hasTaskState.microTask; | 
					
						
							|  |  |  |         this._finishCallbackIfDone(); | 
					
						
							|  |  |  |       } else if (hasTaskState.change == 'macroTask') { | 
					
						
							|  |  |  |         this._pendingMacroTasks = hasTaskState.macroTask; | 
					
						
							|  |  |  |         this._finishCallbackIfDone(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Export the class so that new instances can be created with proper
 | 
					
						
							|  |  |  |   // constructor params.
 | 
					
						
							|  |  |  |   (Zone as any)['AsyncTestZoneSpec'] = AsyncTestZoneSpec; | 
					
						
							| 
									
										
										
										
											2019-07-08 11:30:29 -07:00
										 |  |  | })(typeof window !== 'undefined' && window || typeof self !== 'undefined' && self || global); |