diff --git a/.travis.yml b/.travis.yml
index 802a256f9..2e51e3b18 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -39,9 +39,13 @@ script:
- node_modules/.bin/karma start karma-build-sauce-mocha.conf.js --single-run
- node_modules/.bin/karma start karma-dist-sauce-selenium3-jasmine.conf.js --single-run
- node_modules/.bin/karma start karma-build-sauce-selenium3-mocha.conf.js --single-run
+ - node_modules/.bin/karma start karma-dist-sauce-jasmine3.conf.js --single-run --errorpolicy=disable
+ - node_modules/.bin/karma start karma-dist-sauce-jasmine3.conf.js --single-run --errorpolicy=lazy
- node_modules/.bin/gulp test/node
- node_modules/.bin/gulp test/node -no-patch-clock
- node_modules/.bin/gulp test/bluebird
+ - node_modules/.bin/gulp test/node/disableerror
+ - node_modules/.bin/gulp test/node/lazyerror
- node simple-server.js 2>&1> server.log&
- node ./test/webdriver/test.sauce.js
- yarn add jasmine@3.0.0 jasmine-core@3.0.0 mocha@5.0.1
diff --git a/MODULE.md b/MODULE.md
index 377f66fa9..51519a03e 100644
--- a/MODULE.md
+++ b/MODULE.md
@@ -76,6 +76,57 @@ you can do like this.
```
+- Error
+
+By default, `zone.js/dist/zone-error` will not be loaded for performance concern.
+This package will provide following functionality.
+
+ 1. Error inherit: handle `extend Error` issue.
+ ```
+ class MyError extends Error {}
+ const myError = new MyError();
+ console.log('is MyError instanceof Error', (myError instanceof Error));
+ ```
+
+ without `zone-error` patch, the example above will output `false`, with the patch, the reuslt will be `true`.
+
+ 2. BlacklistZoneStackFrames: remove zone.js stack from `stackTrace`, and add `zone` information. Without this patch, a lot of `zone.js` invocation stack will be shown
+ in stack frames.
+
+ ```
+ at zone.run (polyfill.bundle.js: 3424)
+ at zoneDelegate.invokeTask (polyfill.bundle.js: 3424)
+ at zoneDelegate.runTask (polyfill.bundle.js: 3424)
+ at zone.drainMicroTaskQueue (polyfill.bundle.js: 3424)
+ at a.b.c (vendor.bundle.js: 12345 )
+ at d.e.f (main.bundle.js: 23456)
+ ```
+
+ with this patch, those zone frames will be removed,
+ and the zone information `/` will be added
+
+ ```
+ at a.b.c (vendor.bundle.js: 12345 )
+ at d.e.f (main.bundle.js: 23456 )
+ ```
+
+ The second feature will slow down the `Error` performance, so `zone.js` provide a flag to let you be able to control the behavior.
+ The flag is `__Zone_Error_BlacklistedStackFrames_policy`. And the available options is:
+
+ 1. default: this is the default one, if you load `zone.js/dist/zone-error` without
+ setting the flag, `default` will be used, and `BlackListStackFrames` will be available
+ when `new Error()`, you can get a `error.stack` which is `zone stack free`. But this
+ will slow down `new Error()` a little bit.
+
+ 2. disable: this will disable `BlackListZoneStackFrame` feature, and if you load
+ `zone.js/dist/zone-error`, you will only get a `wrapped Error` which can handle
+ `Error inherit` issue.
+
+ 3. lazy: this is a feature to let you be able to get `BlackListZoneStackFrame` feature,
+ but not impact performance. But as a trade off, you can't get the `zone free stack
+ frames` by access `error.stack`. You can only get it by access `error.zoneAwareStack`.
+
+
- Angular(2+)
Angular uses zone.js to manage async operations and decide when to perform change detection. Thus, in Angular,
diff --git a/file-size-limit.json b/file-size-limit.json
index 2c03611e5..26e5195d5 100644
--- a/file-size-limit.json
+++ b/file-size-limit.json
@@ -3,7 +3,7 @@
{
"path": "dist/zone.min.js",
"checkTarget": true,
- "limit": 40000
+ "limit": 40144
}
]
}
diff --git a/gulpfile.js b/gulpfile.js
index 385bcdde7..64235017b 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -444,6 +444,18 @@ gulp.task('test/bluebird', ['compile-node'], function(cb) {
nodeTest(specFiles, cb);
});
+gulp.task('test/node/disableerror', ['compile-node'], function(cb) {
+ process.env.errorpolicy = 'disable';
+ var specFiles = ['build/test/node_error_entry_point.js'];
+ nodeTest(specFiles, cb);
+});
+
+gulp.task('test/node/lazyerror', ['compile-node'], function(cb) {
+ process.env.errorpolicy = 'lazy';
+ var specFiles = ['build/test/node_error_entry_point.js'];
+ nodeTest(specFiles, cb);
+});
+
// Check the coding standards and programming errors
gulp.task('lint', () => {
const tslint = require('gulp-tslint');
diff --git a/karma-base.conf.js b/karma-base.conf.js
index d31a4310f..32f447cff 100644
--- a/karma-base.conf.js
+++ b/karma-base.conf.js
@@ -9,6 +9,7 @@
module.exports = function(config) {
config.set({
basePath: '',
+ client: {errorpolicy: config.errorpolicy},
files: [
'node_modules/systemjs/dist/system-polyfills.js', 'node_modules/systemjs/dist/system.src.js',
'node_modules/whatwg-fetch/fetch.js',
@@ -41,6 +42,7 @@ module.exports = function(config) {
browsers: ['Chrome'],
captureTimeout: 60000,
+ retryLimit: 4,
autoWatch: true,
singleRun: false
diff --git a/karma-build.conf.js b/karma-build.conf.js
index 87c87a5ea..aa2d3113c 100644
--- a/karma-build.conf.js
+++ b/karma-build.conf.js
@@ -6,12 +6,11 @@
* found in the LICENSE file at https://angular.io/license
*/
-module.exports = function (config) {
+module.exports = function(config) {
require('./karma-base.conf.js')(config);
config.files.push('build/test/wtf_mock.js');
config.files.push('build/test/test_fake_polyfill.js');
config.files.push('build/lib/zone.js');
config.files.push('build/lib/common/promise.js');
- config.files.push('build/lib/common/error-rewrite.js');
config.files.push('build/test/main.js');
};
diff --git a/lib/browser/define-property.ts b/lib/browser/define-property.ts
index 872e86ea9..872631148 100644
--- a/lib/browser/define-property.ts
+++ b/lib/browser/define-property.ts
@@ -19,7 +19,7 @@ const _create = Object.create;
const unconfigurablesKey = zoneSymbol('unconfigurables');
export function propertyPatch() {
- Object.defineProperty = function(obj, prop, desc) {
+ Object.defineProperty = function(obj: any, prop: string, desc: any) {
if (isUnconfigurable(obj, prop)) {
throw new TypeError('Cannot assign to read only property \'' + prop + '\' of ' + obj);
}
diff --git a/lib/common/error-rewrite.ts b/lib/common/error-rewrite.ts
index dc9a48918..1f63473d0 100644
--- a/lib/common/error-rewrite.ts
+++ b/lib/common/error-rewrite.ts
@@ -46,10 +46,71 @@ Zone.__load_patch('Error', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
// We must find the frame where Error was created, otherwise we assume we don't understand stack
let zoneAwareFrame1: string;
let zoneAwareFrame2: string;
+ let zoneAwareFrame1WithoutNew: string;
+ let zoneAwareFrame2WithoutNew: string;
+ let zoneAwareFrame3WithoutNew: string;
global['Error'] = ZoneAwareError;
const stackRewrite = 'stackRewrite';
+ type BlackListedStackFramesPolicy = 'default'|'disable'|'lazy';
+ const blackListedStackFramesPolicy: BlackListedStackFramesPolicy =
+ global['__Zone_Error_BlacklistedStackFrames_policy'] || 'default';
+
+ interface ZoneFrameName {
+ zoneName: string;
+ parent?: ZoneFrameName;
+ }
+
+ function buildZoneFrameNames(zoneFrame: _ZoneFrame) {
+ let zoneFrameName: ZoneFrameName = {zoneName: zoneFrame.zone.name};
+ let result = zoneFrameName;
+ while (zoneFrame.parent) {
+ zoneFrame = zoneFrame.parent;
+ const parentZoneFrameName = {zoneName: zoneFrame.zone.name};
+ zoneFrameName.parent = parentZoneFrameName;
+ zoneFrameName = parentZoneFrameName;
+ }
+ return result;
+ }
+
+ function buildZoneAwareStackFrames(
+ originalStack: string, zoneFrame: _ZoneFrame|ZoneFrameName|null, isZoneFrame = true) {
+ let frames: string[] = originalStack.split('\n');
+ let i = 0;
+ // Find the first frame
+ while (!(frames[i] === zoneAwareFrame1 || frames[i] === zoneAwareFrame2 ||
+ frames[i] === zoneAwareFrame1WithoutNew || frames[i] === zoneAwareFrame2WithoutNew ||
+ frames[i] === zoneAwareFrame3WithoutNew) &&
+ i < frames.length) {
+ i++;
+ }
+ for (; i < frames.length && zoneFrame; i++) {
+ let frame = frames[i];
+ if (frame.trim()) {
+ switch (blackListedStackFrames[frame]) {
+ case FrameType.blackList:
+ frames.splice(i, 1);
+ i--;
+ break;
+ case FrameType.transition:
+ if (zoneFrame.parent) {
+ // This is the special frame where zone changed. Print and process it accordingly
+ zoneFrame = zoneFrame.parent;
+ } else {
+ zoneFrame = null;
+ }
+ frames.splice(i, 1);
+ i--;
+ break;
+ default:
+ frames[i] += isZoneFrame ? ` [${(zoneFrame as _ZoneFrame).zone.name}]` :
+ ` [${(zoneFrame as ZoneFrameName).zoneName}]`;
+ }
+ }
+ }
+ return frames.join('\n');
+ }
/**
* This is ZoneAwareError which processes the stack frame and cleans up extra frames as well as
* adds zone information to it.
@@ -62,42 +123,17 @@ Zone.__load_patch('Error', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
// Process the stack trace and rewrite the frames.
if ((ZoneAwareError as any)[stackRewrite] && originalStack) {
- let frames: string[] = originalStack.split('\n');
- let zoneFrame: _ZoneFrame|null = api.currentZoneFrame();
- let i = 0;
- // Find the first frame
- while (!(frames[i] === zoneAwareFrame1 || frames[i] === zoneAwareFrame2) &&
- i < frames.length) {
- i++;
- }
- for (; i < frames.length && zoneFrame; i++) {
- let frame = frames[i];
- if (frame.trim()) {
- switch (blackListedStackFrames[frame]) {
- case FrameType.blackList:
- frames.splice(i, 1);
- i--;
- break;
- case FrameType.transition:
- if (zoneFrame.parent) {
- // This is the special frame where zone changed. Print and process it accordingly
- zoneFrame = zoneFrame.parent;
- } else {
- zoneFrame = null;
- }
- frames.splice(i, 1);
- i--;
- break;
- default:
- frames[i] += ` [${zoneFrame.zone.name}]`;
- }
+ let zoneFrame = api.currentZoneFrame();
+ if (blackListedStackFramesPolicy === 'lazy') {
+ // don't handle stack trace now
+ (error as any)[api.symbol('zoneFrameNames')] = buildZoneFrameNames(zoneFrame);
+ } else if (blackListedStackFramesPolicy === 'default') {
+ try {
+ error.stack = error.zoneAwareStack = buildZoneAwareStackFrames(originalStack, zoneFrame);
+ } catch (e) {
+ // ignore as some browsers don't allow overriding of stack
}
}
- try {
- error.stack = error.zoneAwareStack = frames.join('\n');
- } catch (e) {
- // ignore as some browsers don't allow overriding of stack
- }
}
if (this instanceof NativeError && this.constructor != NativeError) {
@@ -123,6 +159,29 @@ Zone.__load_patch('Error', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
(ZoneAwareError as any)[blacklistedStackFramesSymbol] = blackListedStackFrames;
(ZoneAwareError as any)[stackRewrite] = false;
+ const zoneAwareStackSymbol = api.symbol('zoneAwareStack');
+
+ // try to define zoneAwareStack property when blackListed
+ // policy is delay
+ if (blackListedStackFramesPolicy === 'lazy') {
+ Object.defineProperty(ZoneAwareError.prototype, 'zoneAwareStack', {
+ configurable: true,
+ enumerable: true,
+ get: function() {
+ if (!this[zoneAwareStackSymbol]) {
+ this[zoneAwareStackSymbol] = buildZoneAwareStackFrames(
+ this.originalStack, this[api.symbol('zoneFrameNames')], false);
+ }
+ return this[zoneAwareStackSymbol];
+ },
+ set: function(newStack: string) {
+ this.originalStack = newStack;
+ this[zoneAwareStackSymbol] = buildZoneAwareStackFrames(
+ this.originalStack, this[api.symbol('zoneFrameNames')], false);
+ }
+ });
+ }
+
// those properties need special handling
const specialPropertyNames = ['stackTraceLimit', 'captureStackTrace', 'prepareStackTrace'];
// those properties of NativeError should be set to ZoneAwareError
@@ -194,65 +253,71 @@ Zone.__load_patch('Error', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
}
});
+ if (blackListedStackFramesPolicy === 'disable') {
+ // don't need to run detectZone to populate
+ // blacklisted stack frames
+ return;
+ }
// Now we need to populate the `blacklistedStackFrames` as well as find the
// run/runGuarded/runTask frames. This is done by creating a detect zone and then threading
// the execution through all of the above methods so that we can look at the stack trace and
// find the frames of interest.
- const ZONE_AWARE_ERROR = 'ZoneAwareError';
- const ERROR_DOT = 'Error.';
- const EMPTY = '';
- const RUN_GUARDED = 'runGuarded';
- const RUN_TASK = 'runTask';
- const RUN = 'run';
- const BRACKETS = '(';
- const AT = '@';
let detectZone: Zone = Zone.current.fork({
name: 'detect',
- onHandleError: function(parentZD: ZoneDelegate, current: Zone, target: Zone, error: any):
- boolean {
- if (error.originalStack && Error === ZoneAwareError) {
- let frames = error.originalStack.split(/\n/);
- let runFrame = false, runGuardedFrame = false, runTaskFrame = false;
- while (frames.length) {
- let frame = frames.shift();
- // On safari it is possible to have stack frame with no line number.
- // This check makes sure that we don't filter frames on name only (must have
- // line number)
- if (/:\d+:\d+/.test(frame)) {
- // Get rid of the path so that we don't accidentally find function name in path.
- // In chrome the separator is `(` and `@` in FF and safari
- // Chrome: at Zone.run (zone.js:100)
- // Chrome: at Zone.run (http://localhost:9876/base/build/lib/zone.js:100:24)
- // FireFox: Zone.prototype.run@http://localhost:9876/base/build/lib/zone.js:101:24
- // Safari: run@http://localhost:9876/base/build/lib/zone.js:101:24
- let fnName: string = frame.split(BRACKETS)[0].split(AT)[0];
- let frameType = FrameType.transition;
- if (fnName.indexOf(ZONE_AWARE_ERROR) !== -1) {
- zoneAwareFrame1 = frame;
- zoneAwareFrame2 = frame.replace(ERROR_DOT, EMPTY);
- blackListedStackFrames[zoneAwareFrame2] = FrameType.blackList;
- }
- if (fnName.indexOf(RUN_GUARDED) !== -1) {
- runGuardedFrame = true;
- } else if (fnName.indexOf(RUN_TASK) !== -1) {
- runTaskFrame = true;
- } else if (fnName.indexOf(RUN) !== -1) {
- runFrame = true;
- } else {
- frameType = FrameType.blackList;
- }
- blackListedStackFrames[frame] = frameType;
- // Once we find all of the frames we can stop looking.
- if (runFrame && runGuardedFrame && runTaskFrame) {
- (ZoneAwareError as any)[stackRewrite] = true;
- break;
+ onHandleError: function(
+ parentZD: ZoneDelegate, current: Zone, target: Zone, error: any): boolean {
+ if (error.originalStack && Error === ZoneAwareError) {
+ let frames = error.originalStack.split(/\n/);
+ let runFrame = false, runGuardedFrame = false, runTaskFrame = false;
+ while (frames.length) {
+ let frame = frames.shift();
+ // On safari it is possible to have stack frame with no line number.
+ // This check makes sure that we don't filter frames on name only (must have
+ // line number or exact equals to `ZoneAwareError`)
+ if (/:\d+:\d+/.test(frame) || frame === 'ZoneAwareError') {
+ // Get rid of the path so that we don't accidentally find function name in path.
+ // In chrome the separator is `(` and `@` in FF and safari
+ // Chrome: at Zone.run (zone.js:100)
+ // Chrome: at Zone.run (http://localhost:9876/base/build/lib/zone.js:100:24)
+ // FireFox: Zone.prototype.run@http://localhost:9876/base/build/lib/zone.js:101:24
+ // Safari: run@http://localhost:9876/base/build/lib/zone.js:101:24
+ let fnName: string = frame.split('(')[0].split('@')[0];
+ let frameType = FrameType.transition;
+ if (fnName.indexOf('ZoneAwareError') !== -1) {
+ if (fnName.indexOf('new ZoneAwareError') !== -1) {
+ zoneAwareFrame1 = frame;
+ zoneAwareFrame2 = frame.replace('new ZoneAwareError', 'new Error.ZoneAwareError');
+ } else {
+ zoneAwareFrame1WithoutNew = frame;
+ zoneAwareFrame2WithoutNew = frame.replace('Error.', '');
+ if (frame.indexOf('Error.ZoneAwareError') === -1) {
+ zoneAwareFrame3WithoutNew =
+ frame.replace('ZoneAwareError', 'Error.ZoneAwareError');
}
}
+ blackListedStackFrames[zoneAwareFrame2] = FrameType.blackList;
+ }
+ if (fnName.indexOf('runGuarded') !== -1) {
+ runGuardedFrame = true;
+ } else if (fnName.indexOf('runTask') !== -1) {
+ runTaskFrame = true;
+ } else if (fnName.indexOf('run') !== -1) {
+ runFrame = true;
+ } else {
+ frameType = FrameType.blackList;
+ }
+ blackListedStackFrames[frame] = frameType;
+ // Once we find all of the frames we can stop looking.
+ if (runFrame && runGuardedFrame && runTaskFrame) {
+ (ZoneAwareError as any)[stackRewrite] = true;
+ break;
}
}
- return false;
}
+ }
+ return false;
+ }
}) as Zone;
// carefully constructor a stack frame which contains all of the frames of interest which
// need to be detected and blacklisted.
@@ -293,7 +358,17 @@ Zone.__load_patch('Error', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
childDetectZone.scheduleMicroTask(
blacklistedStackFramesSymbol,
() => {
- throw new (ZoneAwareError as any)(ZoneAwareError, NativeError);
+ throw new Error();
+ },
+ undefined,
+ (t: Task) => {
+ (t as any)._transitionTo = fakeTransitionTo;
+ t.invoke();
+ });
+ childDetectZone.scheduleMicroTask(
+ blacklistedStackFramesSymbol,
+ () => {
+ throw Error();
},
undefined,
(t: Task) => {
@@ -316,5 +391,6 @@ Zone.__load_patch('Error', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
() => {});
});
});
+
Error.stackTraceLimit = originalStackTraceLimit;
});
diff --git a/lib/common/utils.ts b/lib/common/utils.ts
index e7bbed307..0165da1c0 100644
--- a/lib/common/utils.ts
+++ b/lib/common/utils.ts
@@ -342,10 +342,10 @@ export function copySymbolProperties(src: any, dest: any) {
symbols.forEach((symbol: any) => {
const desc = Object.getOwnPropertyDescriptor(src, symbol);
Object.defineProperty(dest, symbol, {
- get: function () {
+ get: function() {
return src[symbol];
},
- set: function (value: any) {
+ set: function(value: any) {
if (desc && (!desc.writable || typeof desc.set !== 'function')) {
// if src[symbol] is not writable or not have a setter, just return
return;
diff --git a/lib/node/node_util.ts b/lib/node/node_util.ts
index d37aa4aa0..7ea994851 100644
--- a/lib/node/node_util.ts
+++ b/lib/node/node_util.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {setShouldCopySymbolProperties, patchOnProperties, patchMethod, bindArguments} from '../common/utils';
+import {bindArguments, patchMethod, patchOnProperties, setShouldCopySymbolProperties} from '../common/utils';
Zone.__load_patch('node_util', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
api.patchOnProperties = patchOnProperties;
diff --git a/package.json b/package.json
index edcf64c43..533547247 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,7 @@
"dependencies": {},
"devDependencies": {
"@types/jasmine": "2.2.33",
- "@types/node": "^8.10.17",
+ "@types/node": "^9.x",
"@types/systemjs": "^0.19.30",
"assert": "^1.4.1",
"bluebird": "^3.5.1",
diff --git a/sauce-selenium3.conf.js b/sauce-selenium3.conf.js
index d06a50258..0141e8808 100644
--- a/sauce-selenium3.conf.js
+++ b/sauce-selenium3.conf.js
@@ -8,7 +8,7 @@ module.exports = function(config) {
'SL_CHROME60':
{base: 'SauceLabs', browserName: 'Chrome', platform: 'Windows 10', version: '60.0'},
'SL_SAFARI11':
- {base: 'SauceLabs', browserName: 'safari', platform: 'macOS 10.13', version: '11.0'},
+ {base: 'SauceLabs', browserName: 'safari', platform: 'macOS 10.13', version: '11.1'},
};
config.set({
diff --git a/sauce.conf.js b/sauce.conf.js
index 8a1c8a53a..c3ad894fc 100644
--- a/sauce.conf.js
+++ b/sauce.conf.js
@@ -36,7 +36,7 @@ module.exports = function(config, ignoredLaunchers) {
version: '8.4'
},*/
'SL_IOS9': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '9.3'},
- 'SL_IOS10': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '10.2'},
+ 'SL_IOS10': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '10.3'},
'SL_IE9': {
base: 'SauceLabs',
browserName: 'internet explorer',
diff --git a/test/browser/WebSocket.spec.ts b/test/browser/WebSocket.spec.ts
index 82c51c321..86441f2fe 100644
--- a/test/browser/WebSocket.spec.ts
+++ b/test/browser/WebSocket.spec.ts
@@ -47,7 +47,7 @@ if (!window['saucelabs']) {
expect(e.data).toBe('pass');
done();
};
- });
+ }, 10000);
it('should work with addEventListener', function(done) {
testZone.run(function() {
diff --git a/test/common/Error.spec.ts b/test/common/Error.spec.ts
index 540faf82f..3ed1a5713 100644
--- a/test/common/Error.spec.ts
+++ b/test/common/Error.spec.ts
@@ -78,7 +78,15 @@ class TestMessageError extends WrappedError {
describe('ZoneAwareError', () => {
// If the environment does not supports stack rewrites, then these tests will fail
// and there is no point in running them.
- if (!(Error as any)['stackRewrite']) return;
+ const _global: any = typeof window !== 'undefined' ? window : global;
+ let config: any;
+ 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 {}
@@ -180,15 +188,18 @@ describe('ZoneAwareError', () => {
});
it('should show zone names in stack frames and remove extra frames', () => {
+ if (policy === 'disable' || !(Error as any)['stackRewrite']) {
+ return;
+ }
const rootZone = Zone.root;
const innerZone = rootZone.fork({name: 'InnerZone'});
rootZone.run(testFn);
function testFn() {
- let outside: Error;
- let inside: Error;
- let outsideWithoutNew: Error;
- let insideWithoutNew: Error;
+ let outside: any;
+ let inside: any;
+ let outsideWithoutNew: any;
+ let insideWithoutNew: any;
try {
throw new Error('Outside');
} catch (e) {
@@ -212,6 +223,13 @@ describe('ZoneAwareError', () => {
}
});
+ 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);
@@ -251,7 +269,6 @@ describe('ZoneAwareError', () => {
if (/Error /.test(insideWithoutNewFrames[0])) {
insideWithoutNewFrames.shift();
}
-
expect(outsideFrames[0]).toMatch(/testFn.*[]/);
expect(insideFrames[0]).toMatch(/insideRun.*[InnerZone]]/);
@@ -267,13 +284,31 @@ describe('ZoneAwareError', () => {
const zoneAwareFrames = [
'Zone.run', 'Zone.runGuarded', 'Zone.scheduleEventTask', 'Zone.scheduleMicroTask',
'Zone.scheduleMacroTask', 'Zone.runTask', 'ZoneDelegate.scheduleTask',
- 'ZoneDelegate.invokeTask', 'zoneAwareAddListener'
+ '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: Error) {
- const frames = err.stack!.split('\n');
- for (let i = 0; i < frames.length; i++) {
- expect(zoneAwareFrames.filter(f => frames[i].indexOf(f) !== -1)).toEqual([]);
+ 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([]);
+ }
}
};
@@ -317,7 +352,9 @@ describe('ZoneAwareError', () => {
it('Error with new which cause by promise rejection should not have zone frames visible',
(done) => {
const p = new Promise((resolve, reject) => {
- reject(new Error('test error'));
+ setTimeout(() => {
+ reject(new Error('test error'));
+ });
});
p.catch(err => {
assertStackDoesNotContainZoneFrames(err);
@@ -328,7 +365,9 @@ describe('ZoneAwareError', () => {
it('Error without new which cause by promise rejection should not have zone frames visible',
(done) => {
const p = new Promise((resolve, reject) => {
- reject(Error('test error'));
+ setTimeout(() => {
+ reject(Error('test error'));
+ });
});
p.catch(err => {
assertStackDoesNotContainZoneFrames(err);
diff --git a/test/main.ts b/test/main.ts
index 69514966d..ccfedf5a8 100644
--- a/test/main.ts
+++ b/test/main.ts
@@ -13,6 +13,14 @@ declare const __karma__: {
};
__karma__.loaded = function() {};
+
+if (typeof __karma__ !== 'undefined') {
+ (window as any)['__Zone_Error_BlacklistedStackFrames_policy'] =
+ (__karma__ as any).config.errorpolicy;
+} else if (typeof process !== 'undefined') {
+ (window as any)['__Zone_Error_BlacklistedStackFrames_policy'] = process.env.errorpolicy;
+}
+
(window as any).global = window;
System.config({
defaultJSExtensions: true,
@@ -29,7 +37,7 @@ if ((window as any)[(Zone as any).__symbol__('setTimeout')]) {
// this means that Zone has not patched the browser yet, which means we must be running in
// build mode and need to load the browser patch.
browserPatchedPromise = System.import('/base/build/test/browser-zone-setup').then(() => {
- let testFrameworkPatch = typeof(window as any).Mocha !== 'undefined' ?
+ let testFrameworkPatch = typeof (window as any).Mocha !== 'undefined' ?
'/base/build/lib/mocha/mocha' :
'/base/build/lib/jasmine/jasmine';
return System.import(testFrameworkPatch);
@@ -42,13 +50,15 @@ browserPatchedPromise.then(() => {
'/base/build/test/test-env-setup-jasmine';
// Setup test environment
System.import(testFrameworkPatch).then(() => {
- System.import('/base/build/test/browser_entry_point')
- .then(
- () => {
- __karma__.start();
- },
- (error) => {
- console.error(error.stack || error);
- });
+ System.import('/base/build/lib/common/error-rewrite').then(() => {
+ System.import('/base/build/test/browser_entry_point')
+ .then(
+ () => {
+ __karma__.start();
+ },
+ (error) => {
+ console.error(error.stack || error);
+ });
+ });
});
});
diff --git a/test/node/fs.spec.ts b/test/node/fs.spec.ts
index 1ba819dd7..55cd02b24 100644
--- a/test/node/fs.spec.ts
+++ b/test/node/fs.spec.ts
@@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {exists, read, unlink, unwatchFile, watch, write, watchFile, writeFile, openSync, fstatSync, closeSync, unlinkSync} from 'fs';
+import {closeSync, exists, fstatSync, openSync, read, unlink, unlinkSync, unwatchFile, watch, watchFile, write, writeFile} from 'fs';
import * as util from 'util';
describe('nodejs file system', () => {
@@ -94,12 +94,15 @@ describe('nodejs file system', () => {
describe('util.promisify', () => {
it('fs.exists should work with util.promisify', (done: DoneFn) => {
const promisifyExists = util.promisify(exists);
- promisifyExists(__filename).then(r => {
- expect(r).toBe(true);
- done();
- }, err => {
- fail(`should not be here with error: ${err}`);
- });
+ promisifyExists(__filename)
+ .then(
+ r => {
+ expect(r).toBe(true);
+ done();
+ },
+ err => {
+ fail(`should not be here with error: ${err}`);
+ });
});
it('fs.read should work with util.promisify', (done: DoneFn) => {
@@ -111,15 +114,17 @@ describe('util.promisify', () => {
const buffer = new Buffer(bufferSize);
let bytesRead = 0;
// fd, buffer, offset, length, position, callback
- promisifyRead(fd, buffer, bytesRead, chunkSize, bytesRead).then(
- (value) => {
- expect(value.bytesRead).toBe(chunkSize);
- closeSync(fd);
- done();
- }, err => {
- closeSync(fd);
- fail(`should not be here with error: ${error}.`);
- });
+ promisifyRead(fd, buffer, bytesRead, chunkSize, bytesRead)
+ .then(
+ (value) => {
+ expect(value.bytesRead).toBe(chunkSize);
+ closeSync(fd);
+ done();
+ },
+ err => {
+ closeSync(fd);
+ fail(`should not be here with error: ${error}.`);
+ });
});
it('fs.write should work with util.promisify', (done: DoneFn) => {
@@ -133,16 +138,18 @@ describe('util.promisify', () => {
buffer[i] = 0;
}
// fd, buffer, offset, length, position, callback
- promisifyWrite(fd, buffer, 0, chunkSize, 0).then(
- (value) => {
- expect(value.bytesWritten).toBe(chunkSize);
- closeSync(fd);
- unlinkSync(dest);
- done();
- }, err => {
- closeSync(fd);
- unlinkSync(dest);
- fail(`should not be here with error: ${error}.`);
- });
+ promisifyWrite(fd, buffer, 0, chunkSize, 0)
+ .then(
+ (value) => {
+ expect(value.bytesWritten).toBe(chunkSize);
+ closeSync(fd);
+ unlinkSync(dest);
+ done();
+ },
+ err => {
+ closeSync(fd);
+ unlinkSync(dest);
+ fail(`should not be here with error: ${error}.`);
+ });
});
});
\ No newline at end of file
diff --git a/test/node/timer.spec.ts b/test/node/timer.spec.ts
index 082c0af32..eff071905 100644
--- a/test/node/timer.spec.ts
+++ b/test/node/timer.spec.ts
@@ -5,26 +5,31 @@
* 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 { promisify } from 'util';
+import {promisify} from 'util';
describe('node timer', () => {
it('util.promisify should work with setTimeout', (done: DoneFn) => {
const setTimeoutPromise = promisify(setTimeout);
- setTimeoutPromise(50, 'value').then(value => {
- expect(value).toEqual('value');
- done();
- }, error => {
- fail(`should not be here with error: ${error}.`);
- });
+ setTimeoutPromise(50, 'value')
+ .then(
+ value => {
+ expect(value).toEqual('value');
+ done();
+ },
+ error => {
+ fail(`should not be here with error: ${error}.`);
+ });
});
it('util.promisify should work with setImmediate', (done: DoneFn) => {
const setImmediatePromise = promisify(setImmediate);
- setImmediatePromise('value').then(value => {
- expect(value).toEqual('value');
- done();
- }, error => {
- fail(`should not be here with error: ${error}.`);
- });
+ setImmediatePromise('value').then(
+ value => {
+ expect(value).toEqual('value');
+ done();
+ },
+ error => {
+ fail(`should not be here with error: ${error}.`);
+ });
});
});
\ No newline at end of file
diff --git a/test/node_entry_point.ts b/test/node_entry_point.ts
index a98cb3a7c..7d7c4ee79 100644
--- a/test/node_entry_point.ts
+++ b/test/node_entry_point.ts
@@ -20,6 +20,7 @@ import '../lib/zone-spec/task-tracking';
import '../lib/zone-spec/wtf';
import '../lib/rxjs/rxjs';
import '../lib/rxjs/rxjs-fake-async';
+
// Setup test environment
import '../lib/jasmine/jasmine';
import './test-env-setup-jasmine';
diff --git a/test/node_error_entry_point.ts b/test/node_error_entry_point.ts
new file mode 100644
index 000000000..f70682ed9
--- /dev/null
+++ b/test/node_error_entry_point.ts
@@ -0,0 +1,41 @@
+/**
+ * @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
+ */
+
+// Must be loaded before zone loads, so that zone can detect WTF.
+import './wtf_mock';
+import './test_fake_polyfill';
+
+// Setup tests for Zone without microtask support
+import '../lib/zone';
+import '../lib/common/promise';
+import '../lib/common/to-string';
+
+if (typeof __karma__ !== 'undefined') {
+ (global as any)['__Zone_Error_BlacklistedStackFrames_policy'] =
+ (__karma__ as any).config.errorpolicy;
+} else if (typeof process !== 'undefined') {
+ (global as any)['__Zone_Error_BlacklistedStackFrames_policy'] = process.env.errorpolicy;
+}
+
+import '../lib/common/error-rewrite';
+import '../lib/node/node';
+import '../lib/zone-spec/async-test';
+import '../lib/zone-spec/fake-async-test';
+import '../lib/zone-spec/long-stack-trace';
+import '../lib/zone-spec/proxy';
+import '../lib/zone-spec/sync-test';
+import '../lib/zone-spec/task-tracking';
+import '../lib/zone-spec/wtf';
+import '../lib/rxjs/rxjs';
+
+import '../lib/testing/promise-testing';
+// Setup test environment
+import './test-env-setup-jasmine';
+
+// List all tests here:
+import './common/Error.spec';
diff --git a/test/webdriver/test.sauce.js b/test/webdriver/test.sauce.js
index 13c7e80d1..922f91028 100644
--- a/test/webdriver/test.sauce.js
+++ b/test/webdriver/test.sauce.js
@@ -16,10 +16,10 @@ const desiredCapabilities = {
safari8: {browserName: 'safari', platform: 'OS X 10.10', version: '8.0'},
safari9: {browserName: 'safari', platform: 'OS X 10.11', version: '9.0'},
safari10: {browserName: 'safari', platform: 'OS X 10.11', version: '10.0'},
- safari11: {browserName: 'safari', platform: 'macOS 10.13', version: '11.0'},
+ safari11: {browserName: 'safari', platform: 'macOS 10.13', version: '11.1'},
/*ios84: {browserName: 'iphone', platform: 'OS X 10.10', version: '8.4'},*/
ios93: {browserName: 'iphone', platform: 'OS X 10.10', version: '9.3'},
- ios10: {browserName: 'iphone', platform: 'OS X 10.10', version: '10.2'},
+ ios10: {browserName: 'iphone', platform: 'OS X 10.10', version: '10.3'},
ios11: {browserName: 'iphone', platform: 'OS X 10.12', version: '11.2'},
/*
ie9: {
@@ -134,4 +134,4 @@ Promise.all(tasks).then(() => {
} else {
exit(0);
}
-});
\ No newline at end of file
+});
diff --git a/yarn.lock b/yarn.lock
index a5ef50c82..4047760fe 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6,9 +6,9 @@
version "2.2.33"
resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.2.33.tgz#4715cfd2ca7fbd632fc7f1784f13e637bed028c5"
-"@types/node@^8.10.17":
- version "8.10.17"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.17.tgz#d48cf10f0dc6dcf59f827f5a3fc7a4a6004318d3"
+"@types/node@^9.x":
+ version "9.6.22"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.22.tgz#05b55093faaadedea7a4b3f76e9a61346a6dd209"
"@types/systemjs@^0.19.30":
version "0.19.33"