| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							| 
									
										
										
										
											2020-05-19 12:08:49 -07:00
										 |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {isBrowser, isIE, zoneSymbol} from '../../lib/common/utils'; | 
					
						
							|  |  |  | import {ifEnvSupports, isSafari, isSupportSetErrorStack} from '../test-util'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const defineProperty = (Object as any)[zoneSymbol('defineProperty')] || Object.defineProperty; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | describe( | 
					
						
							|  |  |  |     'longStackTraceZone', ifEnvSupports(isSupportSetErrorStack, function() { | 
					
						
							|  |  |  |       let log: Error[]; | 
					
						
							|  |  |  |       let lstz: Zone; | 
					
						
							|  |  |  |       let longStackTraceZoneSpec = (Zone as any)['longStackTraceZoneSpec']; | 
					
						
							|  |  |  |       let defaultTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(function() { | 
					
						
							|  |  |  |         lstz = Zone.current.fork(longStackTraceZoneSpec).fork({ | 
					
						
							|  |  |  |           name: 'long-stack-trace-zone-test', | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |           onHandleError: | 
					
						
							|  |  |  |               (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, error: any): | 
					
						
							|  |  |  |                   boolean => { | 
					
						
							|  |  |  |                     parentZoneDelegate.handleError(targetZone, error); | 
					
						
							|  |  |  |                     log.push(error); | 
					
						
							|  |  |  |                     return false; | 
					
						
							|  |  |  |                   } | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         log = []; | 
					
						
							|  |  |  |         jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |       afterEach(function() { | 
					
						
							|  |  |  |         jasmine.DEFAULT_TIMEOUT_INTERVAL = defaultTimeout; | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |       function expectElapsed(stack: string, expectedCount: number) { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           let actualCount = stack.split('_Elapsed_').length; | 
					
						
							|  |  |  |           if (actualCount !== expectedCount) { | 
					
						
							|  |  |  |             expect(actualCount).toEqual(expectedCount); | 
					
						
							|  |  |  |             console.log(stack); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |           expect(e).toBe(null); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should produce long stack traces', function(done) { | 
					
						
							|  |  |  |         lstz.run(function() { | 
					
						
							|  |  |  |           setTimeout(function() { | 
					
						
							|  |  |  |             setTimeout(function() { | 
					
						
							|  |  |  |               setTimeout(function() { | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |                 expectElapsed(log[0].stack!, 3); | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |                 done(); | 
					
						
							|  |  |  |               }, 0); | 
					
						
							|  |  |  |               throw new Error('Hello'); | 
					
						
							|  |  |  |             }, 0); | 
					
						
							|  |  |  |           }, 0); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should produce long stack traces for optimized eventTask', | 
					
						
							|  |  |  |          ifEnvSupports(() => isBrowser, function() { | 
					
						
							|  |  |  |            lstz.run(function() { | 
					
						
							|  |  |  |              const button = document.createElement('button'); | 
					
						
							|  |  |  |              const clickEvent = document.createEvent('Event'); | 
					
						
							|  |  |  |              clickEvent.initEvent('click', true, true); | 
					
						
							|  |  |  |              document.body.appendChild(button); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |              button.addEventListener('click', function() { | 
					
						
							|  |  |  |                expectElapsed(log[0].stack!, 1); | 
					
						
							|  |  |  |              }); | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |              button.dispatchEvent(clickEvent); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              document.body.removeChild(button); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should not overwrite long stack traces data for different optimized eventTasks', | 
					
						
							|  |  |  |          ifEnvSupports(() => isBrowser, function() { | 
					
						
							|  |  |  |            lstz.run(function() { | 
					
						
							|  |  |  |              const button = document.createElement('button'); | 
					
						
							|  |  |  |              const clickEvent = document.createEvent('Event'); | 
					
						
							|  |  |  |              clickEvent.initEvent('click', true, true); | 
					
						
							|  |  |  |              document.body.appendChild(button); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              const div = document.createElement('div'); | 
					
						
							|  |  |  |              const enterEvent = document.createEvent('Event'); | 
					
						
							|  |  |  |              enterEvent.initEvent('mouseenter', true, true); | 
					
						
							|  |  |  |              document.body.appendChild(div); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |              button.addEventListener('click', function() { | 
					
						
							|  |  |  |                throw new Error('clickError'); | 
					
						
							|  |  |  |              }); | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |              div.addEventListener('mouseenter', function() { | 
					
						
							|  |  |  |                throw new Error('enterError'); | 
					
						
							|  |  |  |              }); | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |              button.dispatchEvent(clickEvent); | 
					
						
							|  |  |  |              div.dispatchEvent(enterEvent); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              expect(log.length).toBe(2); | 
					
						
							|  |  |  |              if (!isSafari() && !isIE()) { | 
					
						
							|  |  |  |                expect(log[0].stack === log[1].stack).toBe(false); | 
					
						
							|  |  |  |              } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              document.body.removeChild(button); | 
					
						
							|  |  |  |              document.body.removeChild(div); | 
					
						
							|  |  |  |            }); | 
					
						
							|  |  |  |          })); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should produce a long stack trace even if stack setter throws', (done) => { | 
					
						
							|  |  |  |         let wasStackAssigned = false; | 
					
						
							|  |  |  |         let error = new Error('Expected error'); | 
					
						
							|  |  |  |         defineProperty(error, 'stack', { | 
					
						
							|  |  |  |           configurable: false, | 
					
						
							|  |  |  |           get: () => 'someStackTrace', | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |           set: (v: any) => { | 
					
						
							|  |  |  |             throw new Error('no writes'); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         lstz.run(() => { | 
					
						
							|  |  |  |           setTimeout(() => { | 
					
						
							|  |  |  |             throw error; | 
					
						
							|  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |         }); | 
					
						
							|  |  |  |         setTimeout(() => { | 
					
						
							|  |  |  |           const e = log[0]; | 
					
						
							|  |  |  |           expect((e as any).longStack).toBeTruthy(); | 
					
						
							|  |  |  |           done(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should produce long stack traces when has uncaught error in promise', function(done) { | 
					
						
							|  |  |  |         lstz.runGuarded(function() { | 
					
						
							|  |  |  |           setTimeout(function() { | 
					
						
							|  |  |  |             setTimeout(function() { | 
					
						
							|  |  |  |               let promise = new Promise(function(resolve, reject) { | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |                 setTimeout(function() { | 
					
						
							|  |  |  |                   reject(new Error('Hello Promise')); | 
					
						
							|  |  |  |                 }, 0); | 
					
						
							|  |  |  |               }); | 
					
						
							|  |  |  |               promise.then(function() { | 
					
						
							|  |  |  |                 fail('should not get here'); | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |               }); | 
					
						
							|  |  |  |               setTimeout(function() { | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |                 expectElapsed(log[0].stack!, 5); | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |                 done(); | 
					
						
							|  |  |  |               }, 0); | 
					
						
							|  |  |  |             }, 0); | 
					
						
							|  |  |  |           }, 0); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should produce long stack traces when handling error in promise', function(done) { | 
					
						
							|  |  |  |         lstz.runGuarded(function() { | 
					
						
							|  |  |  |           setTimeout(function() { | 
					
						
							|  |  |  |             setTimeout(function() { | 
					
						
							|  |  |  |               let promise = new Promise(function(resolve, reject) { | 
					
						
							|  |  |  |                 setTimeout(function() { | 
					
						
							|  |  |  |                   try { | 
					
						
							|  |  |  |                     throw new Error('Hello Promise'); | 
					
						
							|  |  |  |                   } catch (err) { | 
					
						
							|  |  |  |                     reject(err); | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |                 }, 0); | 
					
						
							|  |  |  |               }); | 
					
						
							|  |  |  |               promise.catch(function(error) { | 
					
						
							|  |  |  |                 // should be able to get long stack trace
 | 
					
						
							|  |  |  |                 const longStackFrames: string = longStackTraceZoneSpec.getLongStackTrace(error); | 
					
						
							|  |  |  |                 expectElapsed(longStackFrames, 4); | 
					
						
							|  |  |  |                 done(); | 
					
						
							|  |  |  |               }); | 
					
						
							|  |  |  |             }, 0); | 
					
						
							|  |  |  |           }, 0); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should not produce long stack traces if Error.stackTraceLimit = 0', function(done) { | 
					
						
							|  |  |  |         const originalStackTraceLimit = Error.stackTraceLimit; | 
					
						
							|  |  |  |         lstz.run(function() { | 
					
						
							|  |  |  |           setTimeout(function() { | 
					
						
							|  |  |  |             setTimeout(function() { | 
					
						
							|  |  |  |               setTimeout(function() { | 
					
						
							|  |  |  |                 if (log[0].stack) { | 
					
						
							| 
									
										
										
										
											2020-04-13 16:40:21 -07:00
										 |  |  |                   expectElapsed(log[0].stack!, 1); | 
					
						
							| 
									
										
										
										
											2019-06-01 00:56:07 +09:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 Error.stackTraceLimit = originalStackTraceLimit; | 
					
						
							|  |  |  |                 done(); | 
					
						
							|  |  |  |               }, 0); | 
					
						
							|  |  |  |               Error.stackTraceLimit = 0; | 
					
						
							|  |  |  |               throw new Error('Hello'); | 
					
						
							|  |  |  |             }, 0); | 
					
						
							|  |  |  |           }, 0); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     })); |