2019-05-31 11:56:07 -04:00
|
|
|
/**
|
|
|
|
* @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',
|
2020-04-13 19:40:21 -04:00
|
|
|
onHandleError:
|
|
|
|
(parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, error: any):
|
|
|
|
boolean => {
|
|
|
|
parentZoneDelegate.handleError(targetZone, error);
|
|
|
|
log.push(error);
|
|
|
|
return false;
|
|
|
|
}
|
2019-05-31 11:56:07 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
log = [];
|
|
|
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
|
|
|
|
});
|
|
|
|
|
2020-04-13 19:40:21 -04:00
|
|
|
afterEach(function() {
|
|
|
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = defaultTimeout;
|
|
|
|
});
|
2019-05-31 11:56:07 -04: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 19:40:21 -04:00
|
|
|
expectElapsed(log[0].stack!, 3);
|
2019-05-31 11:56:07 -04: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 19:40:21 -04:00
|
|
|
button.addEventListener('click', function() {
|
|
|
|
expectElapsed(log[0].stack!, 1);
|
|
|
|
});
|
2019-05-31 11:56:07 -04: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 19:40:21 -04:00
|
|
|
button.addEventListener('click', function() {
|
|
|
|
throw new Error('clickError');
|
|
|
|
});
|
2019-05-31 11:56:07 -04:00
|
|
|
|
2020-04-13 19:40:21 -04:00
|
|
|
div.addEventListener('mouseenter', function() {
|
|
|
|
throw new Error('enterError');
|
|
|
|
});
|
2019-05-31 11:56:07 -04: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 19:40:21 -04:00
|
|
|
set: (v: any) => {
|
|
|
|
throw new Error('no writes');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
lstz.run(() => {
|
|
|
|
setTimeout(() => {
|
|
|
|
throw error;
|
|
|
|
});
|
2019-05-31 11:56:07 -04: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 19:40:21 -04:00
|
|
|
setTimeout(function() {
|
|
|
|
reject(new Error('Hello Promise'));
|
|
|
|
}, 0);
|
|
|
|
});
|
|
|
|
promise.then(function() {
|
|
|
|
fail('should not get here');
|
2019-05-31 11:56:07 -04:00
|
|
|
});
|
|
|
|
setTimeout(function() {
|
2020-04-13 19:40:21 -04:00
|
|
|
expectElapsed(log[0].stack!, 5);
|
2019-05-31 11:56:07 -04: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 19:40:21 -04:00
|
|
|
expectElapsed(log[0].stack!, 1);
|
2019-05-31 11:56:07 -04:00
|
|
|
}
|
|
|
|
Error.stackTraceLimit = originalStackTraceLimit;
|
|
|
|
done();
|
|
|
|
}, 0);
|
|
|
|
Error.stackTraceLimit = 0;
|
|
|
|
throw new Error('Hello');
|
|
|
|
}, 0);
|
|
|
|
}, 0);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}));
|