186 lines
6.5 KiB
TypeScript
186 lines
6.5 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, 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',
|
|
onHandleError: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone,
|
|
error: any): 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: 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() {
|
|
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: any) => { 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) {
|
|
// 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) {
|
|
expectElapsed(log[0].stack !, 1);
|
|
}
|
|
Error.stackTraceLimit = originalStackTraceLimit;
|
|
done();
|
|
}, 0);
|
|
Error.stackTraceLimit = 0;
|
|
throw new Error('Hello');
|
|
}, 0);
|
|
}, 0);
|
|
});
|
|
});
|
|
}));
|