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 ; let lstz ; 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' , onHandleError : ( parentZoneDelegate , currentZone , targetZone , error ) : boolean => { parentZoneDelegate . handleError ( targetZone , error ) ; log . push ( error ) ; return false ; } } ) ; log = [ ] ; jasmine . DEFAULT_TIMEOUT_INTERVAL = 10000 ; } ) ; afterEach ( function ( ) { jasmine . DEFAULT_TIMEOUT_INTERVAL = defaultTimeout ; } ) ; function expectElapsed ( stack , expectedCount ) { 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 ( ) { expectElapsed ( log [ 0 ] . stack ! , 3 ) ; 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 ) ; button . addEventListener ( 'click' , function ( ) { expectElapsed ( log [ 0 ] . stack ! , 1 ) ; } ) ; 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 ) ; button . addEventListener ( 'click' , function ( ) { throw new Error ( 'clickError' ) ; } ) ; div . addEventListener ( 'mouseenter' , function ( ) { throw new Error ( 'enterError' ) ; } ) ; 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' , set : ( v ) => { throw new Error ( 'no writes' ) ; } } ) ; lstz . run ( ( ) => { setTimeout ( ( ) => { throw error ; } ) ; } ) ; 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 ) { setTimeout ( function ( ) { reject ( new Error ( 'Hello Promise' ) ) ; } , 0 ) ; } ) ; promise . then ( function ( ) { fail ( 'should not get here' ) ; } ) ; setTimeout ( function ( ) { expectElapsed ( log [ 0 ] . stack ! , 5 ) ; 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 ) { const longStackFrames = 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 ) { expectElapsed ( log [ 0 ] . stack ! , 1 ) ; } Error . stackTraceLimit = originalStackTraceLimit ; done ( ) ; } , 0 ) ; Error . stackTraceLimit = 0 ; throw new Error ( 'Hello' ) ; } , 0 ) ; } , 0 ) ; } ) ; } ) ; } ) ) ;