8
8
9
9
'use strict' ;
10
10
11
- Zone . __load_patch ( 'jest' , ( context : any , Zone : ZoneType ) => {
11
+ Zone . __load_patch ( 'jest' , ( context : any , Zone : ZoneType , api : _ZonePrivate ) => {
12
12
if ( typeof jest === 'undefined' || jest [ '__zone_patch__' ] ) {
13
13
return ;
14
14
}
15
15
16
16
jest [ '__zone_patch__' ] = true ;
17
17
18
-
19
- if ( typeof Zone === 'undefined' ) {
20
- throw new Error ( 'Missing Zone.js' ) ;
21
- }
22
-
23
18
const ProxyZoneSpec = ( Zone as any ) [ 'ProxyZoneSpec' ] ;
24
19
const SyncTestZoneSpec = ( Zone as any ) [ 'SyncTestZoneSpec' ] ;
25
20
@@ -29,7 +24,8 @@ Zone.__load_patch('jest', (context: any, Zone: ZoneType) => {
29
24
30
25
const rootZone = Zone . current ;
31
26
const syncZone = rootZone . fork ( new SyncTestZoneSpec ( 'jest.describe' ) ) ;
32
- const proxyZone = rootZone . fork ( new ProxyZoneSpec ( ) ) ;
27
+ const proxyZoneSpec = new ProxyZoneSpec ( ) ;
28
+ const proxyZone = rootZone . fork ( proxyZoneSpec ) ;
33
29
34
30
function wrapDescribeFactoryInZone ( originalJestFn : Function ) {
35
31
return function ( this : unknown , ...tableArgs : any [ ] ) {
@@ -65,11 +61,20 @@ Zone.__load_patch('jest', (context: any, Zone: ZoneType) => {
65
61
* execute in a ProxyZone zone.
66
62
* This will run in the `proxyZone`.
67
63
*/
68
- function wrapTestInZone ( testBody : Function ) : Function {
64
+ function wrapTestInZone ( testBody : Function , isTestFunc = false ) : Function {
69
65
if ( typeof testBody !== 'function' ) {
70
66
return testBody ;
71
67
}
72
68
const wrappedFunc = function ( ) {
69
+ if ( ( Zone as any ) [ api . symbol ( 'useFakeTimersCalled' ) ] === true && testBody &&
70
+ ! ( testBody as any ) . isFakeAsync ) {
71
+ // jest.useFakeTimers is called, run into fakeAsyncTest automatically.
72
+ const fakeAsyncModule = ( Zone as any ) [ Zone . __symbol__ ( 'fakeAsyncTest' ) ] ;
73
+ if ( fakeAsyncModule && typeof fakeAsyncModule . fakeAsync === 'function' ) {
74
+ testBody = fakeAsyncModule . fakeAsync ( testBody ) ;
75
+ }
76
+ }
77
+ proxyZoneSpec . isTestFunc = isTestFunc ;
73
78
return proxyZone . run ( testBody , null , arguments as any ) ;
74
79
} ;
75
80
// Update the length of wrappedFunc to be the same as the length of the testBody
@@ -102,7 +107,7 @@ Zone.__load_patch('jest', (context: any, Zone: ZoneType) => {
102
107
}
103
108
context [ Zone . __symbol__ ( methodName ) ] = originalJestFn ;
104
109
context [ methodName ] = function ( this : unknown , ...args : any [ ] ) {
105
- args [ 1 ] = wrapTestInZone ( args [ 1 ] ) ;
110
+ args [ 1 ] = wrapTestInZone ( args [ 1 ] , true ) ;
106
111
return originalJestFn . apply ( this , args ) ;
107
112
} ;
108
113
context [ methodName ] . each = wrapTestFactoryInZone ( ( originalJestFn as any ) . each ) ;
@@ -125,4 +130,165 @@ Zone.__load_patch('jest', (context: any, Zone: ZoneType) => {
125
130
return originalJestFn . apply ( this , args ) ;
126
131
} ;
127
132
} ) ;
133
+
134
+ ( Zone as any ) . patchJestObject = function patchJestObject ( Timer : any , isModern = false ) {
135
+ // check whether currently the test is inside fakeAsync()
136
+ function isPatchingFakeTimer ( ) {
137
+ const fakeAsyncZoneSpec = Zone . current . get ( 'FakeAsyncTestZoneSpec' ) ;
138
+ return ! ! fakeAsyncZoneSpec ;
139
+ }
140
+
141
+ // check whether the current function is inside `test/it` or other methods
142
+ // such as `describe/beforeEach`
143
+ function isInTestFunc ( ) {
144
+ const proxyZoneSpec = Zone . current . get ( 'ProxyZoneSpec' ) ;
145
+ return proxyZoneSpec && proxyZoneSpec . isTestFunc ;
146
+ }
147
+
148
+ if ( Timer [ api . symbol ( 'fakeTimers' ) ] ) {
149
+ return ;
150
+ }
151
+
152
+ Timer [ api . symbol ( 'fakeTimers' ) ] = true ;
153
+ // patch jest fakeTimer internal method to make sure no console.warn print out
154
+ api . patchMethod ( Timer , '_checkFakeTimers' , delegate => {
155
+ return function ( self : any , args : any [ ] ) {
156
+ if ( isPatchingFakeTimer ( ) ) {
157
+ return true ;
158
+ } else {
159
+ return delegate . apply ( self , args ) ;
160
+ }
161
+ }
162
+ } ) ;
163
+
164
+ // patch useFakeTimers(), set useFakeTimersCalled flag, and make test auto run into fakeAsync
165
+ api . patchMethod ( Timer , 'useFakeTimers' , delegate => {
166
+ return function ( self : any , args : any [ ] ) {
167
+ ( Zone as any ) [ api . symbol ( 'useFakeTimersCalled' ) ] = true ;
168
+ if ( isModern || isInTestFunc ( ) ) {
169
+ return delegate . apply ( self , args ) ;
170
+ }
171
+ return self ;
172
+ }
173
+ } ) ;
174
+
175
+ // patch useRealTimers(), unset useFakeTimers flag
176
+ api . patchMethod ( Timer , 'useRealTimers' , delegate => {
177
+ return function ( self : any , args : any [ ] ) {
178
+ ( Zone as any ) [ api . symbol ( 'useFakeTimersCalled' ) ] = false ;
179
+ if ( isModern || isInTestFunc ( ) ) {
180
+ return delegate . apply ( self , args ) ;
181
+ }
182
+ return self ;
183
+ }
184
+ } ) ;
185
+
186
+ // patch setSystemTime(), call setCurrentRealTime() in the fakeAsyncTest
187
+ api . patchMethod ( Timer , 'setSystemTime' , delegate => {
188
+ return function ( self : any , args : any [ ] ) {
189
+ const fakeAsyncZoneSpec = Zone . current . get ( 'FakeAsyncTestZoneSpec' ) ;
190
+ if ( fakeAsyncZoneSpec && isPatchingFakeTimer ( ) ) {
191
+ fakeAsyncZoneSpec . setCurrentRealTime ( args [ 0 ] ) ;
192
+ } else {
193
+ return delegate . apply ( self , args ) ;
194
+ }
195
+ }
196
+ } ) ;
197
+
198
+ // patch getSystemTime(), call getCurrentRealTime() in the fakeAsyncTest
199
+ api . patchMethod ( Timer , 'getRealSystemTime' , delegate => {
200
+ return function ( self : any , args : any [ ] ) {
201
+ const fakeAsyncZoneSpec = Zone . current . get ( 'FakeAsyncTestZoneSpec' ) ;
202
+ if ( fakeAsyncZoneSpec && isPatchingFakeTimer ( ) ) {
203
+ return fakeAsyncZoneSpec . getCurrentRealTime ( args [ 0 ] ) ;
204
+ } else {
205
+ return delegate . apply ( self , args ) ;
206
+ }
207
+ }
208
+ } ) ;
209
+
210
+ // patch runAllTicks(), run all microTasks inside fakeAsync
211
+ api . patchMethod ( Timer , 'runAllTicks' , delegate => {
212
+ return function ( self : any , args : any [ ] ) {
213
+ const fakeAsyncZoneSpec = Zone . current . get ( 'FakeAsyncTestZoneSpec' ) ;
214
+ if ( fakeAsyncZoneSpec ) {
215
+ fakeAsyncZoneSpec . flushMicrotasks ( ) ;
216
+ } else {
217
+ return delegate . apply ( self , args ) ;
218
+ }
219
+ }
220
+ } ) ;
221
+
222
+ // patch runAllTimers(), run all macroTasks inside fakeAsync
223
+ api . patchMethod ( Timer , 'runAllTimers' , delegate => {
224
+ return function ( self : any , args : any [ ] ) {
225
+ const fakeAsyncZoneSpec = Zone . current . get ( 'FakeAsyncTestZoneSpec' ) ;
226
+ if ( fakeAsyncZoneSpec ) {
227
+ fakeAsyncZoneSpec . flush ( 100 , true ) ;
228
+ } else {
229
+ return delegate . apply ( self , args ) ;
230
+ }
231
+ }
232
+ } ) ;
233
+
234
+ // patch advanceTimersByTime(), call tick() in the fakeAsyncTest
235
+ api . patchMethod ( Timer , 'advanceTimersByTime' , delegate => {
236
+ return function ( self : any , args : any [ ] ) {
237
+ const fakeAsyncZoneSpec = Zone . current . get ( 'FakeAsyncTestZoneSpec' ) ;
238
+ if ( fakeAsyncZoneSpec ) {
239
+ fakeAsyncZoneSpec . tick ( args [ 0 ] ) ;
240
+ } else {
241
+ return delegate . apply ( self , args ) ;
242
+ }
243
+ }
244
+ } ) ;
245
+
246
+ // patch runOnlyPendingTimers(), call flushOnlyPendingTimers() in the fakeAsyncTest
247
+ api . patchMethod ( Timer , 'runOnlyPendingTimers' , delegate => {
248
+ return function ( self : any , args : any [ ] ) {
249
+ const fakeAsyncZoneSpec = Zone . current . get ( 'FakeAsyncTestZoneSpec' ) ;
250
+ if ( fakeAsyncZoneSpec ) {
251
+ fakeAsyncZoneSpec . flushOnlyPendingTimers ( ) ;
252
+ } else {
253
+ return delegate . apply ( self , args ) ;
254
+ }
255
+ }
256
+ } ) ;
257
+
258
+ // patch advanceTimersToNextTimer(), call tickToNext() in the fakeAsyncTest
259
+ api . patchMethod ( Timer , 'advanceTimersToNextTimer' , delegate => {
260
+ return function ( self : any , args : any [ ] ) {
261
+ const fakeAsyncZoneSpec = Zone . current . get ( 'FakeAsyncTestZoneSpec' ) ;
262
+ if ( fakeAsyncZoneSpec ) {
263
+ fakeAsyncZoneSpec . tickToNext ( args [ 0 ] ) ;
264
+ } else {
265
+ return delegate . apply ( self , args ) ;
266
+ }
267
+ }
268
+ } ) ;
269
+
270
+ // patch clearAllTimers(), call removeAllTimers() in the fakeAsyncTest
271
+ api . patchMethod ( Timer , 'clearAllTimers' , delegate => {
272
+ return function ( self : any , args : any [ ] ) {
273
+ const fakeAsyncZoneSpec = Zone . current . get ( 'FakeAsyncTestZoneSpec' ) ;
274
+ if ( fakeAsyncZoneSpec ) {
275
+ fakeAsyncZoneSpec . removeAllTimers ( ) ;
276
+ } else {
277
+ return delegate . apply ( self , args ) ;
278
+ }
279
+ }
280
+ } ) ;
281
+
282
+ // patch getTimerCount(), call getTimerCount() in the fakeAsyncTest
283
+ api . patchMethod ( Timer , 'getTimerCount' , delegate => {
284
+ return function ( self : any , args : any [ ] ) {
285
+ const fakeAsyncZoneSpec = Zone . current . get ( 'FakeAsyncTestZoneSpec' ) ;
286
+ if ( fakeAsyncZoneSpec ) {
287
+ return fakeAsyncZoneSpec . getTimerCount ( ) ;
288
+ } else {
289
+ return delegate . apply ( self , args ) ;
290
+ }
291
+ }
292
+ } ) ;
293
+ }
128
294
} ) ;
0 commit comments