angular-cn/packages/zone.js/test/zone-spec/long-stack-trace-zone.spec.ts

205 lines
6.7 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);
});
});
}));