7
7
*/
8
8
9
9
class AsyncTestZoneSpec implements ZoneSpec {
10
+ static symbolParentUnresolved = Zone . __symbol__ ( 'parentUnresolved' ) ;
11
+
10
12
_finishCallback : Function ;
11
13
_failCallback : Function ;
12
14
_pendingMicroTasks : boolean = false ;
13
15
_pendingMacroTasks : boolean = false ;
14
16
_alreadyErrored : boolean = false ;
15
17
runZone = Zone . current ;
18
+ unresolvedChainedPromiseCount = 0 ;
16
19
17
20
constructor ( finishCallback : Function , failCallback : Function , namePrefix : string ) {
18
21
this . _finishCallback = finishCallback ;
19
22
this . _failCallback = failCallback ;
20
23
this . name = 'asyncTestZone for ' + namePrefix ;
24
+ this . properties = {
25
+ 'AsyncTestZoneSpec' : this
26
+ } ;
21
27
}
22
28
23
29
_finishCallbackIfDone ( ) {
24
- if ( ! ( this . _pendingMicroTasks || this . _pendingMacroTasks ) ) {
30
+ if ( ! ( this . _pendingMicroTasks || this . _pendingMacroTasks || this . unresolvedChainedPromiseCount !== 0 ) ) {
25
31
// We do this because we would like to catch unhandled rejected promises.
26
32
this . runZone . run ( ( ) => {
27
33
setTimeout ( ( ) => {
@@ -33,19 +39,48 @@ class AsyncTestZoneSpec implements ZoneSpec {
33
39
}
34
40
}
35
41
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
+
36
56
// ZoneSpec implementation below.
37
57
38
58
name : string ;
39
59
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
+
40
73
// Note - we need to use onInvoke at the moment to call finish when a test is
41
74
// fully synchronous. TODO(juliemr): remove this when the logic for
42
75
// onHasTask changes and it calls whenever the task queues are dirty.
43
76
onInvoke (
44
77
parentZoneDelegate : ZoneDelegate , currentZone : Zone , targetZone : Zone , delegate : Function ,
45
78
applyThis : any , applyArgs : any [ ] , source : string ) : any {
46
79
try {
80
+ this . patchPromiseForTest ( ) ;
47
81
return parentZoneDelegate . invoke ( targetZone , delegate , applyThis , applyArgs , source ) ;
48
82
} finally {
83
+ this . unPatchPromiseForTest ( ) ;
49
84
this . _finishCallbackIfDone ( ) ;
50
85
}
51
86
}
0 commit comments