77 */
88
99class AsyncTestZoneSpec implements ZoneSpec {
10+ static symbolParentUnresolved = Zone . __symbol__ ( 'parentUnresolved' ) ;
11+
1012 _finishCallback : Function ;
1113 _failCallback : Function ;
1214 _pendingMicroTasks : boolean = false ;
1315 _pendingMacroTasks : boolean = false ;
1416 _alreadyErrored : boolean = false ;
1517 runZone = Zone . current ;
18+ unresolvedChainedPromiseCount = 0 ;
1619
1720 constructor ( finishCallback : Function , failCallback : Function , namePrefix : string ) {
1821 this . _finishCallback = finishCallback ;
1922 this . _failCallback = failCallback ;
2023 this . name = 'asyncTestZone for ' + namePrefix ;
24+ this . properties = {
25+ 'AsyncTestZoneSpec' : this
26+ } ;
2127 }
2228
2329 _finishCallbackIfDone ( ) {
24- if ( ! ( this . _pendingMicroTasks || this . _pendingMacroTasks ) ) {
30+ if ( ! ( this . _pendingMicroTasks || this . _pendingMacroTasks || this . unresolvedChainedPromiseCount !== 0 ) ) {
2531 // We do this because we would like to catch unhandled rejected promises.
2632 this . runZone . run ( ( ) => {
2733 setTimeout ( ( ) => {
@@ -33,19 +39,48 @@ class AsyncTestZoneSpec implements ZoneSpec {
3339 }
3440 }
3541
42+ patchPromiseForTest ( ) {
43+ const patchPromiseForTest = ( Promise as any ) [ Zone . __symbol__ ( 'patchPromiseForTest' ) ] ;
44+ if ( patchPromiseForTest ) {
45+ patchPromiseForTest ( ) ;
46+ }
47+ }
48+
49+ unPatchPromiseForTest ( ) {
50+ const unPatchPromiseForTest = ( Promise as any ) [ Zone . __symbol__ ( 'unPatchPromiseForTest' ) ] ;
51+ if ( unPatchPromiseForTest ) {
52+ unPatchPromiseForTest ( ) ;
53+ }
54+ }
55+
3656 // ZoneSpec implementation below.
3757
3858 name : string ;
3959
60+ properties : { [ key : string ] : any } ;
61+
62+ onScheduleTask ( delegate : ZoneDelegate , current : Zone , target : Zone , task : Task ) : Task {
63+ if ( task . type === 'microTask' && task . data && task . data instanceof Promise ) {
64+ // check whether the promise is a chained promise
65+ if ( ( task . data as any ) [ AsyncTestZoneSpec . symbolParentUnresolved ] === true ) {
66+ // chained promise is being scheduled
67+ this . unresolvedChainedPromiseCount -- ;
68+ }
69+ }
70+ return delegate . scheduleTask ( target , task ) ;
71+ }
72+
4073 // Note - we need to use onInvoke at the moment to call finish when a test is
4174 // fully synchronous. TODO(juliemr): remove this when the logic for
4275 // onHasTask changes and it calls whenever the task queues are dirty.
4376 onInvoke (
4477 parentZoneDelegate : ZoneDelegate , currentZone : Zone , targetZone : Zone , delegate : Function ,
4578 applyThis : any , applyArgs : any [ ] , source : string ) : any {
4679 try {
80+ this . patchPromiseForTest ( ) ;
4781 return parentZoneDelegate . invoke ( targetZone , delegate , applyThis , applyArgs , source ) ;
4882 } finally {
83+ this . unPatchPromiseForTest ( ) ;
4984 this . _finishCallbackIfDone ( ) ;
5085 }
5186 }
0 commit comments