@@ -258,12 +258,161 @@ describe('ZoneAwareError', () => {
258
258
expect ( outsideFrames [ 0 ] ) . toMatch ( / t e s t F n .* [ < r o o t > ] / ) ;
259
259
260
260
expect ( insideFrames [ 0 ] ) . toMatch ( / i n s i d e R u n .* [ I n n e r Z o n e ] ] / ) ;
261
- expect ( insideFrames [ 2 ] ) . toMatch ( / t e s t F n .* [ < r o o t > ] ] / ) ;
261
+ expect ( insideFrames [ 1 ] ) . toMatch ( / t e s t F n .* [ < r o o t > ] ] / ) ;
262
262
263
263
expect ( outsideWithoutNewFrames [ 0 ] ) . toMatch ( / t e s t F n .* [ < r o o t > ] / ) ;
264
264
265
265
expect ( insideWithoutNewFrames [ 0 ] ) . toMatch ( / i n s i d e R u n .* [ I n n e r Z o n e ] ] / ) ;
266
- expect ( insideWithoutNewFrames [ 2 ] ) . toMatch ( / t e s t F n .* [ < r o o t > ] ] / ) ;
266
+ expect ( insideWithoutNewFrames [ 1 ] ) . toMatch ( / t e s t F n .* [ < r o o t > ] ] / ) ;
267
267
}
268
268
} ) ;
269
+
270
+ const zoneAwareFrames = [
271
+ 'Zone.run' , 'Zone.runGuarded' , 'Zone.scheduleEventTask' , 'Zone.scheduleMicroTask' ,
272
+ 'Zone.scheduleMacroTask' , 'Zone.runTask' , 'ZoneDelegate.scheduleTask' ,
273
+ 'ZoneDelegate.invokeTask' , 'zoneAwareAddListener'
274
+ ] ;
275
+
276
+ function assertStackDoesNotContainZoneFrames ( err : Error ) {
277
+ const frames = err . stack . split ( '\n' ) ;
278
+ for ( let i = 0 ; i < frames . length ; i ++ ) {
279
+ expect ( zoneAwareFrames . filter ( f => frames [ i ] . indexOf ( f ) !== - 1 ) ) . toEqual ( [ ] ) ;
280
+ }
281
+ } ;
282
+
283
+ const errorZoneSpec = {
284
+ name : 'errorZone' ,
285
+ done : < ( ) => void > null ,
286
+ onHandleError :
287
+ ( parentDelegate : ZoneDelegate , currentZone : Zone , targetZone : Zone , error : Error ) => {
288
+ assertStackDoesNotContainZoneFrames ( error ) ;
289
+ setTimeout ( ( ) => {
290
+ errorZoneSpec . done && errorZoneSpec . done ( ) ;
291
+ } , 0 ) ;
292
+ return false ;
293
+ }
294
+ } ;
295
+
296
+ const errorZone = Zone . root . fork ( errorZoneSpec ) ;
297
+
298
+ const assertStackDoesNotContainZoneFramesTest = function ( testFn : Function ) {
299
+ return function ( done : ( ) => void ) {
300
+ errorZoneSpec . done = done ;
301
+ errorZone . run ( testFn ) ;
302
+ } ;
303
+ } ;
304
+
305
+ describe ( 'Error stack' , ( ) => {
306
+ it ( 'Error with new which occurs in setTimeout callback should not have zone frames visible' ,
307
+ assertStackDoesNotContainZoneFramesTest ( ( ) => {
308
+ setTimeout ( ( ) => {
309
+ throw new Error ( 'timeout test error' ) ;
310
+ } , 10 ) ;
311
+ } ) ) ;
312
+
313
+ it ( 'Error without new which occurs in setTimeout callback should not have zone frames visible' ,
314
+ assertStackDoesNotContainZoneFramesTest ( ( ) => {
315
+ setTimeout ( ( ) => {
316
+ throw Error ( 'test error' ) ;
317
+ } , 10 ) ;
318
+ } ) ) ;
319
+
320
+ it ( 'Error with new which cause by promise rejection should not have zone frames visible' ,
321
+ ( done ) => {
322
+ const p = new Promise ( ( resolve , reject ) => {
323
+ reject ( new Error ( 'test error' ) ) ;
324
+ } ) ;
325
+ p . catch ( err => {
326
+ assertStackDoesNotContainZoneFrames ( err ) ;
327
+ done ( ) ;
328
+ } ) ;
329
+ } ) ;
330
+
331
+ it ( 'Error without new which cause by promise rejection should not have zone frames visible' ,
332
+ ( done ) => {
333
+ const p = new Promise ( ( resolve , reject ) => {
334
+ reject ( Error ( 'test error' ) ) ;
335
+ } ) ;
336
+ p . catch ( err => {
337
+ assertStackDoesNotContainZoneFrames ( err ) ;
338
+ done ( ) ;
339
+ } ) ;
340
+ } ) ;
341
+
342
+ it ( 'Error with new which occurs in eventTask callback should not have zone frames visible' ,
343
+ assertStackDoesNotContainZoneFramesTest ( ( ) => {
344
+ const task = Zone . current . scheduleEventTask ( 'errorEvent' , ( ) => {
345
+ throw new Error ( 'test error' ) ;
346
+ } , null , ( ) => null , null ) ;
347
+ task . invoke ( ) ;
348
+ } ) ) ;
349
+
350
+ it ( 'Error without new which occurs in eventTask callback should not have zone frames visible' ,
351
+ assertStackDoesNotContainZoneFramesTest ( ( ) => {
352
+ const task = Zone . current . scheduleEventTask ( 'errorEvent' , ( ) => {
353
+ throw Error ( 'test error' ) ;
354
+ } , null , ( ) => null , null ) ;
355
+ task . invoke ( ) ;
356
+ } ) ) ;
357
+
358
+ it ( 'Error with new which occurs in longStackTraceZone should not have zone frames and longStackTraceZone frames visible' ,
359
+ assertStackDoesNotContainZoneFramesTest ( ( ) => {
360
+ const task = Zone . current . fork ( ( Zone as any ) [ 'longStackTraceZoneSpec' ] )
361
+ . scheduleEventTask ( 'errorEvent' , ( ) => {
362
+ throw new Error ( 'test error' ) ;
363
+ } , null , ( ) => null , null ) ;
364
+ task . invoke ( ) ;
365
+ } ) ) ;
366
+
367
+ it ( 'Error without new which occurs in longStackTraceZone should not have zone frames and longStackTraceZone frames visible' ,
368
+ assertStackDoesNotContainZoneFramesTest ( ( ) => {
369
+ const task = Zone . current . fork ( ( Zone as any ) [ 'longStackTraceZoneSpec' ] )
370
+ . scheduleEventTask ( 'errorEvent' , ( ) => {
371
+ throw Error ( 'test error' ) ;
372
+ } , null , ( ) => null , null ) ;
373
+ task . invoke ( ) ;
374
+ } ) ) ;
375
+
376
+ it ( 'stack frames of the callback in user customized zoneSpec should be kept' ,
377
+ assertStackDoesNotContainZoneFramesTest ( ( ) => {
378
+ const task = Zone . current . fork ( ( Zone as any ) [ 'longStackTraceZoneSpec' ] )
379
+ . fork ( {
380
+ name : 'customZone' ,
381
+ onScheduleTask : ( parentDelegate , currentZone , targetZone , task ) => {
382
+ return parentDelegate . scheduleTask ( targetZone , task ) ;
383
+ } ,
384
+ onHandleError : ( parentDelegate , currentZone , targetZone , error ) => {
385
+ parentDelegate . handleError ( targetZone , error ) ;
386
+ const containsCustomZoneSpecStackTrace =
387
+ error . stack . indexOf ( 'onScheduleTask' ) !== - 1 ;
388
+ expect ( containsCustomZoneSpecStackTrace ) . toBeTruthy ( ) ;
389
+ return false ;
390
+ }
391
+ } )
392
+ . scheduleEventTask ( 'errorEvent' , ( ) => {
393
+ throw new Error ( 'test error' ) ;
394
+ } , null , ( ) => null , null ) ;
395
+ task . invoke ( ) ;
396
+ } ) ) ;
397
+
398
+ it ( 'should be able to generate zone free stack even NativeError stack is readonly' , function ( ) {
399
+ const _global : any =
400
+ typeof window === 'object' && window || typeof self === 'object' && self || global ;
401
+ const NativeError = _global [ '__zone_symbol__Error' ] ;
402
+ const desc = Object . getOwnPropertyDescriptor ( NativeError . prototype , 'stack' ) ;
403
+ if ( desc ) {
404
+ const originalSet : ( value : any ) => void = desc . set ;
405
+ // make stack readonly
406
+ desc . set = null ;
407
+
408
+ try {
409
+ const error = new Error ( 'test error' ) ;
410
+ expect ( error . stack ) . toBeTruthy ( ) ;
411
+ assertStackDoesNotContainZoneFrames ( error ) ;
412
+ } finally {
413
+ desc . set = originalSet ;
414
+ }
415
+ }
416
+ } ) ;
417
+ } ) ;
269
418
} ) ;
0 commit comments