426 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			426 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * @license
							 | 
						||
| 
								 | 
							
								 * Copyright Google Inc. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * 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} from '../../lib/common/utils';
							 | 
						||
| 
								 | 
							
								import {isSafari, zoneSymbol} from '../test-util';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// simulate @angular/facade/src/error.ts
							 | 
						||
| 
								 | 
							
								class BaseError extends Error {
							 | 
						||
| 
								 | 
							
								  /** @internal **/
							 | 
						||
| 
								 | 
							
								  _nativeError: Error;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor(message: string) {
							 | 
						||
| 
								 | 
							
								    super(message);
							 | 
						||
| 
								 | 
							
								    const nativeError = new Error(message) as any as Error;
							 | 
						||
| 
								 | 
							
								    this._nativeError = nativeError;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  get message() { return this._nativeError.message; }
							 | 
						||
| 
								 | 
							
								  set message(message) { this._nativeError.message = message; }
							 | 
						||
| 
								 | 
							
								  get name() { return this._nativeError.name; }
							 | 
						||
| 
								 | 
							
								  get stack() { return (this._nativeError as any).stack; }
							 | 
						||
| 
								 | 
							
								  set stack(value) { (this._nativeError as any).stack = value; }
							 | 
						||
| 
								 | 
							
								  toString() { return this._nativeError.toString(); }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class WrappedError extends BaseError {
							 | 
						||
| 
								 | 
							
								  originalError: any;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  constructor(message: string, error: any) {
							 | 
						||
| 
								 | 
							
								    super(`${message} caused by: ${error instanceof Error ? error.message : error}`);
							 | 
						||
| 
								 | 
							
								    this.originalError = error;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  get stack() {
							 | 
						||
| 
								 | 
							
								    return ((this.originalError instanceof Error ? this.originalError : this._nativeError) as any)
							 | 
						||
| 
								 | 
							
								        .stack;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class TestError extends WrappedError {
							 | 
						||
| 
								 | 
							
								  constructor(message: string, error: any) {
							 | 
						||
| 
								 | 
							
								    super(`${message} caused by: ${error instanceof Error ? error.message : error}`, error);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  get message() { return 'test ' + this.originalError.message; }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class TestMessageError extends WrappedError {
							 | 
						||
| 
								 | 
							
								  constructor(message: string, error: any) {
							 | 
						||
| 
								 | 
							
								    super(`${message} caused by: ${error instanceof Error ? error.message : error}`, error);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  get message() { return 'test ' + this.originalError.message; }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  set message(value) { this.originalError.message = value; }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								describe('ZoneAwareError', () => {
							 | 
						||
| 
								 | 
							
								  // If the environment does not supports stack rewrites, then these tests will fail
							 | 
						||
| 
								 | 
							
								  // and there is no point in running them.
							 | 
						||
| 
								 | 
							
								  const _global: any = typeof window !== 'undefined' ? window : global;
							 | 
						||
| 
								 | 
							
								  let config: any;
							 | 
						||
| 
								 | 
							
								  const __karma__ = _global.__karma__;
							 | 
						||
| 
								 | 
							
								  if (typeof __karma__ !== 'undefined') {
							 | 
						||
| 
								 | 
							
								    config = __karma__ && (__karma__ as any).config;
							 | 
						||
| 
								 | 
							
								  } else if (typeof process !== 'undefined') {
							 | 
						||
| 
								 | 
							
								    config = process.env;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  const policy = (config && config['errorpolicy']) || 'default';
							 | 
						||
| 
								 | 
							
								  if (!(Error as any)['stackRewrite'] && policy !== 'disable') return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should keep error prototype chain correctly', () => {
							 | 
						||
| 
								 | 
							
								    class MyError extends Error {}
							 | 
						||
| 
								 | 
							
								    const myError = new MyError();
							 | 
						||
| 
								 | 
							
								    expect(myError instanceof Error).toBe(true);
							 | 
						||
| 
								 | 
							
								    expect(myError instanceof MyError).toBe(true);
							 | 
						||
| 
								 | 
							
								    expect(myError.stack).not.toBe(undefined);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should instanceof error correctly', () => {
							 | 
						||
| 
								 | 
							
								    let myError = Error('myError');
							 | 
						||
| 
								 | 
							
								    expect(myError instanceof Error).toBe(true);
							 | 
						||
| 
								 | 
							
								    let myError1 = Error.call(undefined, 'myError');
							 | 
						||
| 
								 | 
							
								    expect(myError1 instanceof Error).toBe(true);
							 | 
						||
| 
								 | 
							
								    let myError2 = Error.call(global, 'myError');
							 | 
						||
| 
								 | 
							
								    expect(myError2 instanceof Error).toBe(true);
							 | 
						||
| 
								 | 
							
								    let myError3 = Error.call({}, 'myError');
							 | 
						||
| 
								 | 
							
								    expect(myError3 instanceof Error).toBe(true);
							 | 
						||
| 
								 | 
							
								    let myError4 = Error.call({test: 'test'}, 'myError');
							 | 
						||
| 
								 | 
							
								    expect(myError4 instanceof Error).toBe(true);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should return error itself from constructor', () => {
							 | 
						||
| 
								 | 
							
								    class MyError1 extends Error {
							 | 
						||
| 
								 | 
							
								      constructor() {
							 | 
						||
| 
								 | 
							
								        const err: any = super('MyError1');
							 | 
						||
| 
								 | 
							
								        this.message = err.message;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    let myError1 = new MyError1();
							 | 
						||
| 
								 | 
							
								    expect(myError1.message).toEqual('MyError1');
							 | 
						||
| 
								 | 
							
								    expect(myError1.name).toEqual('Error');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should return error by calling error directly', () => {
							 | 
						||
| 
								 | 
							
								    let myError = Error('myError');
							 | 
						||
| 
								 | 
							
								    expect(myError.message).toEqual('myError');
							 | 
						||
| 
								 | 
							
								    let myError1 = Error.call(undefined, 'myError');
							 | 
						||
| 
								 | 
							
								    expect(myError1.message).toEqual('myError');
							 | 
						||
| 
								 | 
							
								    let myError2 = Error.call(global, 'myError');
							 | 
						||
| 
								 | 
							
								    expect(myError2.message).toEqual('myError');
							 | 
						||
| 
								 | 
							
								    let myError3 = Error.call({}, 'myError');
							 | 
						||
| 
								 | 
							
								    expect(myError3.message).toEqual('myError');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should have browser specified property', () => {
							 | 
						||
| 
								 | 
							
								    let myError = new Error('myError');
							 | 
						||
| 
								 | 
							
								    if (Object.prototype.hasOwnProperty.call(Error.prototype, 'description')) {
							 | 
						||
| 
								 | 
							
								      // in IE, error has description property
							 | 
						||
| 
								 | 
							
								      expect((<any>myError).description).toEqual('myError');
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (Object.prototype.hasOwnProperty.call(Error.prototype, 'fileName')) {
							 | 
						||
| 
								 | 
							
								      // in firefox, error has fileName property
							 | 
						||
| 
								 | 
							
								      expect((<any>myError).fileName).toBeTruthy();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should not use child Error class get/set in ZoneAwareError constructor', () => {
							 | 
						||
| 
								 | 
							
								    const func = () => {
							 | 
						||
| 
								 | 
							
								      const error = new BaseError('test');
							 | 
						||
| 
								 | 
							
								      expect(error.message).toEqual('test');
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    expect(func).not.toThrow();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should behave correctly with wrapped error', () => {
							 | 
						||
| 
								 | 
							
								    const error = new TestError('originalMessage', new Error('error message'));
							 | 
						||
| 
								 | 
							
								    expect(error.message).toEqual('test error message');
							 | 
						||
| 
								 | 
							
								    error.originalError.message = 'new error message';
							 | 
						||
| 
								 | 
							
								    expect(error.message).toEqual('test new error message');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    const error1 = new TestMessageError('originalMessage', new Error('error message'));
							 | 
						||
| 
								 | 
							
								    expect(error1.message).toEqual('test error message');
							 | 
						||
| 
								 | 
							
								    error1.message = 'new error message';
							 | 
						||
| 
								 | 
							
								    expect(error1.message).toEqual('test new error message');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should copy customized NativeError properties to ZoneAwareError', () => {
							 | 
						||
| 
								 | 
							
								    const spy = jasmine.createSpy('errorCustomFunction');
							 | 
						||
| 
								 | 
							
								    const NativeError = (global as any)[(Zone as any).__symbol__('Error')];
							 | 
						||
| 
								 | 
							
								    NativeError.customFunction = function(args: any) { spy(args); };
							 | 
						||
| 
								 | 
							
								    expect((Error as any)['customProperty']).toBe('customProperty');
							 | 
						||
| 
								 | 
							
								    expect(typeof(Error as any)['customFunction']).toBe('function');
							 | 
						||
| 
								 | 
							
								    (Error as any)['customFunction']('test');
							 | 
						||
| 
								 | 
							
								    expect(spy).toHaveBeenCalledWith('test');
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should always have stack property even without throw', () => {
							 | 
						||
| 
								 | 
							
								    // in IE, the stack will be undefined without throw
							 | 
						||
| 
								 | 
							
								    // in ZoneAwareError, we will make stack always be
							 | 
						||
| 
								 | 
							
								    // there event without throw
							 | 
						||
| 
								 | 
							
								    const error = new Error('test');
							 | 
						||
| 
								 | 
							
								    const errorWithoutNew = Error('test');
							 | 
						||
| 
								 | 
							
								    expect(error.stack !.split('\n').length > 0).toBeTruthy();
							 | 
						||
| 
								 | 
							
								    expect(errorWithoutNew.stack !.split('\n').length > 0).toBeTruthy();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  it('should show zone names in stack frames and remove extra frames', () => {
							 | 
						||
| 
								 | 
							
								    if (policy === 'disable' || !(Error as any)['stackRewrite']) {
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (isBrowser && isSafari()) {
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    const rootZone = Zone.root;
							 | 
						||
| 
								 | 
							
								    const innerZone = rootZone.fork({name: 'InnerZone'});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    rootZone.run(testFn);
							 | 
						||
| 
								 | 
							
								    function testFn() {
							 | 
						||
| 
								 | 
							
								      let outside: any;
							 | 
						||
| 
								 | 
							
								      let inside: any;
							 | 
						||
| 
								 | 
							
								      let outsideWithoutNew: any;
							 | 
						||
| 
								 | 
							
								      let insideWithoutNew: any;
							 | 
						||
| 
								 | 
							
								      try {
							 | 
						||
| 
								 | 
							
								        throw new Error('Outside');
							 | 
						||
| 
								 | 
							
								      } catch (e) {
							 | 
						||
| 
								 | 
							
								        outside = e;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      try {
							 | 
						||
| 
								 | 
							
								        throw Error('Outside');
							 | 
						||
| 
								 | 
							
								      } catch (e) {
							 | 
						||
| 
								 | 
							
								        outsideWithoutNew = e;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      innerZone.run(function insideRun() {
							 | 
						||
| 
								 | 
							
								        try {
							 | 
						||
| 
								 | 
							
								          throw new Error('Inside');
							 | 
						||
| 
								 | 
							
								        } catch (e) {
							 | 
						||
| 
								 | 
							
								          inside = e;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        try {
							 | 
						||
| 
								 | 
							
								          throw Error('Inside');
							 | 
						||
| 
								 | 
							
								        } catch (e) {
							 | 
						||
| 
								 | 
							
								          insideWithoutNew = e;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (policy === 'lazy') {
							 | 
						||
| 
								 | 
							
								        outside.stack = outside.zoneAwareStack;
							 | 
						||
| 
								 | 
							
								        outsideWithoutNew.stack = outsideWithoutNew.zoneAwareStack;
							 | 
						||
| 
								 | 
							
								        inside.stack = inside.zoneAwareStack;
							 | 
						||
| 
								 | 
							
								        insideWithoutNew.stack = insideWithoutNew.zoneAwareStack;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      expect(outside.stack).toEqual(outside.zoneAwareStack);
							 | 
						||
| 
								 | 
							
								      expect(outsideWithoutNew.stack).toEqual(outsideWithoutNew.zoneAwareStack);
							 | 
						||
| 
								 | 
							
								      expect(inside !.stack).toEqual(inside !.zoneAwareStack);
							 | 
						||
| 
								 | 
							
								      expect(insideWithoutNew !.stack).toEqual(insideWithoutNew !.zoneAwareStack);
							 | 
						||
| 
								 | 
							
								      expect(typeof inside !.originalStack).toEqual('string');
							 | 
						||
| 
								 | 
							
								      expect(typeof insideWithoutNew !.originalStack).toEqual('string');
							 | 
						||
| 
								 | 
							
								      const outsideFrames = outside.stack !.split(/\n/);
							 | 
						||
| 
								 | 
							
								      const insideFrames = inside !.stack !.split(/\n/);
							 | 
						||
| 
								 | 
							
								      const outsideWithoutNewFrames = outsideWithoutNew !.stack !.split(/\n/);
							 | 
						||
| 
								 | 
							
								      const insideWithoutNewFrames = insideWithoutNew !.stack !.split(/\n/);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // throw away first line if it contains the error
							 | 
						||
| 
								 | 
							
								      if (/Outside/.test(outsideFrames[0])) {
							 | 
						||
| 
								 | 
							
								        outsideFrames.shift();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      if (/Error /.test(outsideFrames[0])) {
							 | 
						||
| 
								 | 
							
								        outsideFrames.shift();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (/Outside/.test(outsideWithoutNewFrames[0])) {
							 | 
						||
| 
								 | 
							
								        outsideWithoutNewFrames.shift();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      if (/Error /.test(outsideWithoutNewFrames[0])) {
							 | 
						||
| 
								 | 
							
								        outsideWithoutNewFrames.shift();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (/Inside/.test(insideFrames[0])) {
							 | 
						||
| 
								 | 
							
								        insideFrames.shift();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      if (/Error /.test(insideFrames[0])) {
							 | 
						||
| 
								 | 
							
								        insideFrames.shift();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (/Inside/.test(insideWithoutNewFrames[0])) {
							 | 
						||
| 
								 | 
							
								        insideWithoutNewFrames.shift();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      if (/Error /.test(insideWithoutNewFrames[0])) {
							 | 
						||
| 
								 | 
							
								        insideWithoutNewFrames.shift();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      expect(outsideFrames[0]).toMatch(/testFn.*[<root>]/);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      expect(insideFrames[0]).toMatch(/insideRun.*[InnerZone]]/);
							 | 
						||
| 
								 | 
							
								      expect(insideFrames[1]).toMatch(/testFn.*[<root>]]/);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      expect(outsideWithoutNewFrames[0]).toMatch(/testFn.*[<root>]/);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      expect(insideWithoutNewFrames[0]).toMatch(/insideRun.*[InnerZone]]/);
							 | 
						||
| 
								 | 
							
								      expect(insideWithoutNewFrames[1]).toMatch(/testFn.*[<root>]]/);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const zoneAwareFrames = [
							 | 
						||
| 
								 | 
							
								    'Zone.run', 'Zone.runGuarded', 'Zone.scheduleEventTask', 'Zone.scheduleMicroTask',
							 | 
						||
| 
								 | 
							
								    'Zone.scheduleMacroTask', 'Zone.runTask', 'ZoneDelegate.scheduleTask',
							 | 
						||
| 
								 | 
							
								    'ZoneDelegate.invokeTask', 'zoneAwareAddListener', 'Zone.prototype.run',
							 | 
						||
| 
								 | 
							
								    'Zone.prototype.runGuarded', 'Zone.prototype.scheduleEventTask',
							 | 
						||
| 
								 | 
							
								    'Zone.prototype.scheduleMicroTask', 'Zone.prototype.scheduleMacroTask',
							 | 
						||
| 
								 | 
							
								    'Zone.prototype.runTask', 'ZoneDelegate.prototype.scheduleTask',
							 | 
						||
| 
								 | 
							
								    'ZoneDelegate.prototype.invokeTask', 'ZoneTask.invokeTask'
							 | 
						||
| 
								 | 
							
								  ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function assertStackDoesNotContainZoneFrames(err: any) {
							 | 
						||
| 
								 | 
							
								    const frames = policy === 'lazy' ? err.zoneAwareStack.split('\n') : err.stack.split('\n');
							 | 
						||
| 
								 | 
							
								    if (policy === 'disable') {
							 | 
						||
| 
								 | 
							
								      let hasZoneStack = false;
							 | 
						||
| 
								 | 
							
								      for (let i = 0; i < frames.length; i++) {
							 | 
						||
| 
								 | 
							
								        if (hasZoneStack) {
							 | 
						||
| 
								 | 
							
								          break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        hasZoneStack = zoneAwareFrames.filter(f => frames[i].indexOf(f) !== -1).length > 0;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      if (!hasZoneStack) {
							 | 
						||
| 
								 | 
							
								        console.log('stack', err.originalStack);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      expect(hasZoneStack).toBe(true);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      for (let i = 0; i < frames.length; i++) {
							 | 
						||
| 
								 | 
							
								        expect(zoneAwareFrames.filter(f => frames[i].indexOf(f) !== -1)).toEqual([]);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const errorZoneSpec = {
							 | 
						||
| 
								 | 
							
								    name: 'errorZone',
							 | 
						||
| 
								 | 
							
								    done: <(() => void)|null>null,
							 | 
						||
| 
								 | 
							
								    onHandleError:
							 | 
						||
| 
								 | 
							
								        (parentDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, error: Error) => {
							 | 
						||
| 
								 | 
							
								          assertStackDoesNotContainZoneFrames(error);
							 | 
						||
| 
								 | 
							
								          setTimeout(() => { errorZoneSpec.done && errorZoneSpec.done(); }, 0);
							 | 
						||
| 
								 | 
							
								          return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const errorZone = Zone.root.fork(errorZoneSpec);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const assertStackDoesNotContainZoneFramesTest = function(testFn: Function) {
							 | 
						||
| 
								 | 
							
								    return function(done: () => void) {
							 | 
						||
| 
								 | 
							
								      errorZoneSpec.done = done;
							 | 
						||
| 
								 | 
							
								      errorZone.run(testFn);
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  describe('Error stack', () => {
							 | 
						||
| 
								 | 
							
								    it('Error with new which occurs in setTimeout callback should not have zone frames visible',
							 | 
						||
| 
								 | 
							
								       assertStackDoesNotContainZoneFramesTest(
							 | 
						||
| 
								 | 
							
								           () => { setTimeout(() => { throw new Error('timeout test error'); }, 10); }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('Error without new which occurs in setTimeout callback should not have zone frames visible',
							 | 
						||
| 
								 | 
							
								       assertStackDoesNotContainZoneFramesTest(
							 | 
						||
| 
								 | 
							
								           () => { setTimeout(() => { throw Error('test error'); }, 10); }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('Error with new which cause by promise rejection should not have zone frames visible',
							 | 
						||
| 
								 | 
							
								       (done) => {
							 | 
						||
| 
								 | 
							
								         const p = new Promise(
							 | 
						||
| 
								 | 
							
								             (resolve, reject) => { setTimeout(() => { reject(new Error('test error')); }); });
							 | 
						||
| 
								 | 
							
								         p.catch(err => {
							 | 
						||
| 
								 | 
							
								           assertStackDoesNotContainZoneFrames(err);
							 | 
						||
| 
								 | 
							
								           done();
							 | 
						||
| 
								 | 
							
								         });
							 | 
						||
| 
								 | 
							
								       });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('Error without new which cause by promise rejection should not have zone frames visible',
							 | 
						||
| 
								 | 
							
								       (done) => {
							 | 
						||
| 
								 | 
							
								         const p = new Promise(
							 | 
						||
| 
								 | 
							
								             (resolve, reject) => { setTimeout(() => { reject(Error('test error')); }); });
							 | 
						||
| 
								 | 
							
								         p.catch(err => {
							 | 
						||
| 
								 | 
							
								           assertStackDoesNotContainZoneFrames(err);
							 | 
						||
| 
								 | 
							
								           done();
							 | 
						||
| 
								 | 
							
								         });
							 | 
						||
| 
								 | 
							
								       });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('Error with new which occurs in eventTask callback should not have zone frames visible',
							 | 
						||
| 
								 | 
							
								       assertStackDoesNotContainZoneFramesTest(() => {
							 | 
						||
| 
								 | 
							
								         const task = Zone.current.scheduleEventTask('errorEvent', () => {
							 | 
						||
| 
								 | 
							
								           throw new Error('test error');
							 | 
						||
| 
								 | 
							
								         }, undefined, () => null, undefined);
							 | 
						||
| 
								 | 
							
								         task.invoke();
							 | 
						||
| 
								 | 
							
								       }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('Error without new which occurs in eventTask callback should not have zone frames visible',
							 | 
						||
| 
								 | 
							
								       assertStackDoesNotContainZoneFramesTest(() => {
							 | 
						||
| 
								 | 
							
								         const task = Zone.current.scheduleEventTask(
							 | 
						||
| 
								 | 
							
								             'errorEvent', () => { throw Error('test error'); }, undefined, () => null, undefined);
							 | 
						||
| 
								 | 
							
								         task.invoke();
							 | 
						||
| 
								 | 
							
								       }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('Error with new which occurs in longStackTraceZone should not have zone frames and longStackTraceZone frames visible',
							 | 
						||
| 
								 | 
							
								       assertStackDoesNotContainZoneFramesTest(() => {
							 | 
						||
| 
								 | 
							
								         const task = Zone.current.fork((Zone as any)['longStackTraceZoneSpec'])
							 | 
						||
| 
								 | 
							
								                          .scheduleEventTask('errorEvent', () => {
							 | 
						||
| 
								 | 
							
								                            throw new Error('test error');
							 | 
						||
| 
								 | 
							
								                          }, undefined, () => null, undefined);
							 | 
						||
| 
								 | 
							
								         task.invoke();
							 | 
						||
| 
								 | 
							
								       }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('Error without new which occurs in longStackTraceZone should not have zone frames and longStackTraceZone frames visible',
							 | 
						||
| 
								 | 
							
								       assertStackDoesNotContainZoneFramesTest(() => {
							 | 
						||
| 
								 | 
							
								         const task = Zone.current.fork((Zone as any)['longStackTraceZoneSpec'])
							 | 
						||
| 
								 | 
							
								                          .scheduleEventTask('errorEvent', () => {
							 | 
						||
| 
								 | 
							
								                            throw Error('test error');
							 | 
						||
| 
								 | 
							
								                          }, undefined, () => null, undefined);
							 | 
						||
| 
								 | 
							
								         task.invoke();
							 | 
						||
| 
								 | 
							
								       }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('stack frames of the callback in user customized zoneSpec should be kept',
							 | 
						||
| 
								 | 
							
								       assertStackDoesNotContainZoneFramesTest(() => {
							 | 
						||
| 
								 | 
							
								         const task = Zone.current.fork((Zone as any)['longStackTraceZoneSpec'])
							 | 
						||
| 
								 | 
							
								                          .fork({
							 | 
						||
| 
								 | 
							
								                            name: 'customZone',
							 | 
						||
| 
								 | 
							
								                            onScheduleTask: (parentDelegate, currentZone, targetZone, task) => {
							 | 
						||
| 
								 | 
							
								                              return parentDelegate.scheduleTask(targetZone, task);
							 | 
						||
| 
								 | 
							
								                            },
							 | 
						||
| 
								 | 
							
								                            onHandleError: (parentDelegate, currentZone, targetZone, error) => {
							 | 
						||
| 
								 | 
							
								                              parentDelegate.handleError(targetZone, error);
							 | 
						||
| 
								 | 
							
								                              const containsCustomZoneSpecStackTrace =
							 | 
						||
| 
								 | 
							
								                                  error.stack.indexOf('onScheduleTask') !== -1;
							 | 
						||
| 
								 | 
							
								                              expect(containsCustomZoneSpecStackTrace).toBeTruthy();
							 | 
						||
| 
								 | 
							
								                              return false;
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                          })
							 | 
						||
| 
								 | 
							
								                          .scheduleEventTask('errorEvent', () => {
							 | 
						||
| 
								 | 
							
								                            throw new Error('test error');
							 | 
						||
| 
								 | 
							
								                          }, undefined, () => null, undefined);
							 | 
						||
| 
								 | 
							
								         task.invoke();
							 | 
						||
| 
								 | 
							
								       }));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    it('should be able to generate zone free stack even NativeError stack is readonly', function() {
							 | 
						||
| 
								 | 
							
								      const _global: any =
							 | 
						||
| 
								 | 
							
								          typeof window === 'object' && window || typeof self === 'object' && self || global;
							 | 
						||
| 
								 | 
							
								      const NativeError = _global[zoneSymbol('Error')];
							 | 
						||
| 
								 | 
							
								      const desc = Object.getOwnPropertyDescriptor(NativeError.prototype, 'stack');
							 | 
						||
| 
								 | 
							
								      if (desc) {
							 | 
						||
| 
								 | 
							
								        const originalSet: ((value: any) => void)|undefined = desc.set;
							 | 
						||
| 
								 | 
							
								        // make stack readonly
							 | 
						||
| 
								 | 
							
								        desc.set = null as any;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        try {
							 | 
						||
| 
								 | 
							
								          const error = new Error('test error');
							 | 
						||
| 
								 | 
							
								          expect(error.stack).toBeTruthy();
							 | 
						||
| 
								 | 
							
								          assertStackDoesNotContainZoneFrames(error);
							 | 
						||
| 
								 | 
							
								        } finally {
							 | 
						||
| 
								 | 
							
								          desc.set = originalSet;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								});
							 |