feat(zone): add support for long stack traces
This commit is contained in:
parent
d5fcac4d7a
commit
df21c3c77d
|
@ -31,6 +31,7 @@ var _HTLM_DEFAULT_SCRIPTS_JS = [
|
||||||
{src: '/rtts_assert/lib/rtts_assert.js', mimeType: 'text/javascript'},
|
{src: '/rtts_assert/lib/rtts_assert.js', mimeType: 'text/javascript'},
|
||||||
{src: '/deps/es6-module-loader-sans-promises.src.js', mimeType: 'text/javascript'},
|
{src: '/deps/es6-module-loader-sans-promises.src.js', mimeType: 'text/javascript'},
|
||||||
{src: '/deps/zone.js', mimeType: 'text/javascript'},
|
{src: '/deps/zone.js', mimeType: 'text/javascript'},
|
||||||
|
{src: '/deps/long-stack-trace-zone.js', mimeType: 'text/javascript'},
|
||||||
{src: '/deps/system.src.js', mimeType: 'text/javascript'},
|
{src: '/deps/system.src.js', mimeType: 'text/javascript'},
|
||||||
{src: '/deps/extension-register.js', mimeType: 'text/javascript'},
|
{src: '/deps/extension-register.js', mimeType: 'text/javascript'},
|
||||||
{src: '/deps/runtime_paths.js', mimeType: 'text/javascript'},
|
{src: '/deps/runtime_paths.js', mimeType: 'text/javascript'},
|
||||||
|
@ -68,6 +69,7 @@ var CONFIG = {
|
||||||
"node_modules/systemjs/dist/system.src.js",
|
"node_modules/systemjs/dist/system.src.js",
|
||||||
"node_modules/systemjs/lib/extension-register.js",
|
"node_modules/systemjs/lib/extension-register.js",
|
||||||
"node_modules/zone.js/zone.js",
|
"node_modules/zone.js/zone.js",
|
||||||
|
"node_modules/zone.js/long-stack-trace-zone.js",
|
||||||
"tools/build/runtime_paths.js",
|
"tools/build/runtime_paths.js",
|
||||||
"node_modules/angular/angular.js"
|
"node_modules/angular/angular.js"
|
||||||
]
|
]
|
||||||
|
|
|
@ -20,6 +20,7 @@ module.exports = function(config) {
|
||||||
'node_modules/systemjs/dist/system.src.js',
|
'node_modules/systemjs/dist/system.src.js',
|
||||||
'node_modules/systemjs/lib/extension-register.js',
|
'node_modules/systemjs/lib/extension-register.js',
|
||||||
'node_modules/zone.js/zone.js',
|
'node_modules/zone.js/zone.js',
|
||||||
|
'node_modules/zone.js/long-stack-trace-zone.js',
|
||||||
|
|
||||||
'tools/build/file2modulename.js',
|
'tools/build/file2modulename.js',
|
||||||
'test-main.js'
|
'test-main.js'
|
||||||
|
|
|
@ -2,6 +2,7 @@ name: core
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=1.4.0'
|
sdk: '>=1.4.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
|
stack_trace: '1.1.1'
|
||||||
change_detection:
|
change_detection:
|
||||||
path: ../change_detection
|
path: ../change_detection
|
||||||
di:
|
di:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {Injector, bind, OpaqueToken} from 'di/di';
|
import {Injector, bind, OpaqueToken} from 'di/di';
|
||||||
import {Type, FIELD, isBlank, isPresent, BaseException, assertionsEnabled} from 'facade/lang';
|
import {Type, FIELD, isBlank, isPresent, BaseException, assertionsEnabled, print} from 'facade/lang';
|
||||||
import {DOM, Element} from 'facade/dom';
|
import {DOM, Element} from 'facade/dom';
|
||||||
import {Compiler, CompilerCache} from './compiler/compiler';
|
import {Compiler, CompilerCache} from './compiler/compiler';
|
||||||
import {ProtoView} from './compiler/view';
|
import {ProtoView} from './compiler/view';
|
||||||
|
@ -11,7 +11,8 @@ import {RecordRange} from 'change_detection/record_range';
|
||||||
import {TemplateLoader} from './compiler/template_loader';
|
import {TemplateLoader} from './compiler/template_loader';
|
||||||
import {DirectiveMetadataReader} from './compiler/directive_metadata_reader';
|
import {DirectiveMetadataReader} from './compiler/directive_metadata_reader';
|
||||||
import {AnnotatedType} from './compiler/annotated_type';
|
import {AnnotatedType} from './compiler/annotated_type';
|
||||||
import {ListWrapper} from 'facade/collection';
|
import {List, ListWrapper} from 'facade/collection';
|
||||||
|
import {PromiseWrapper} from 'facade/async';
|
||||||
import {VmTurnZone} from 'core/zone/vm_turn_zone';
|
import {VmTurnZone} from 'core/zone/vm_turn_zone';
|
||||||
import {LifeCycle} from 'core/life_cycle/life_cycle';
|
import {LifeCycle} from 'core/life_cycle/life_cycle';
|
||||||
|
|
||||||
|
@ -77,24 +78,47 @@ function _injectorBindings(appComponentType) {
|
||||||
documentDependentBindings(appComponentType));
|
documentDependentBindings(appComponentType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _createVmZone(givenReporter:Function){
|
||||||
|
var defaultErrorReporter = (exception, stackTrace) => {
|
||||||
|
var longStackTrace = ListWrapper.join(stackTrace, "\n\n-----async gap-----\n");
|
||||||
|
print(`${exception}\n\n${longStackTrace}`);
|
||||||
|
throw exception;
|
||||||
|
};
|
||||||
|
|
||||||
|
var reporter = isPresent(givenReporter) ? givenReporter : defaultErrorReporter;
|
||||||
|
|
||||||
|
var zone = new VmTurnZone({enableLongStackTrace: assertionsEnabled()});
|
||||||
|
zone.initCallbacks({onErrorHandler: reporter});
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
// Multiple calls to this method are allowed. Each application would only share
|
// Multiple calls to this method are allowed. Each application would only share
|
||||||
// _rootInjector, which is not user-configurable by design, thus safe to share.
|
// _rootInjector, which is not user-configurable by design, thus safe to share.
|
||||||
export function bootstrap(appComponentType: Type, bindings=null) {
|
export function bootstrap(appComponentType: Type, bindings=null, givenBootstrapErrorReporter=null) {
|
||||||
// TODO(rado): prepopulate template cache, so applications with only
|
var bootstrapProcess = PromiseWrapper.completer();
|
||||||
// index.html and main.js are possible.
|
|
||||||
|
var zone = _createVmZone(givenBootstrapErrorReporter);
|
||||||
|
zone.run(() => {
|
||||||
|
// TODO(rado): prepopulate template cache, so applications with only
|
||||||
|
// index.html and main.js are possible.
|
||||||
|
|
||||||
var zone = new VmTurnZone();
|
|
||||||
return zone.run(() => {
|
|
||||||
if (isBlank(_rootInjector)) _rootInjector = new Injector(_rootBindings);
|
if (isBlank(_rootInjector)) _rootInjector = new Injector(_rootBindings);
|
||||||
|
|
||||||
var appInjector = _rootInjector.createChild(_injectorBindings(appComponentType));
|
var appInjector = _rootInjector.createChild(_injectorBindings(appComponentType));
|
||||||
if (isPresent(bindings)) appInjector = appInjector.createChild(bindings);
|
if (isPresent(bindings)) appInjector = appInjector.createChild(bindings);
|
||||||
|
|
||||||
return appInjector.asyncGet(LifeCycle).
|
PromiseWrapper.then(appInjector.asyncGet(LifeCycle),
|
||||||
then((lc) => {
|
(lc) => {
|
||||||
lc.registerWith(zone);
|
lc.registerWith(zone);
|
||||||
lc.tick();
|
lc.tick(); //the first tick that will bootstrap the app
|
||||||
}).
|
|
||||||
then((_) => appInjector);
|
bootstrapProcess.complete(appInjector);
|
||||||
|
},
|
||||||
|
|
||||||
|
(err) => {
|
||||||
|
bootstrapProcess.reject(err)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return bootstrapProcess.promise;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {FIELD} from 'facade/lang';
|
import {FIELD, print} from 'facade/lang';
|
||||||
import {ChangeDetector} from 'change_detection/change_detector';
|
import {ChangeDetector} from 'change_detection/change_detector';
|
||||||
import {VmTurnZone} from 'core/zone/vm_turn_zone';
|
import {VmTurnZone} from 'core/zone/vm_turn_zone';
|
||||||
|
import {ListWrapper} from 'facade/collection';
|
||||||
|
|
||||||
export class LifeCycle {
|
export class LifeCycle {
|
||||||
_changeDetector:ChangeDetector;
|
_changeDetector:ChangeDetector;
|
||||||
|
@ -10,7 +11,15 @@ export class LifeCycle {
|
||||||
}
|
}
|
||||||
|
|
||||||
registerWith(zone:VmTurnZone) {
|
registerWith(zone:VmTurnZone) {
|
||||||
|
// temporary error handler, we should inject one
|
||||||
|
var errorHandler = (exception, stackTrace) => {
|
||||||
|
var longStackTrace = ListWrapper.join(stackTrace, "\n\n-----async gap-----\n");
|
||||||
|
print(`${exception}\n\n${longStackTrace}`);
|
||||||
|
throw exception;
|
||||||
|
};
|
||||||
|
|
||||||
zone.initCallbacks({
|
zone.initCallbacks({
|
||||||
|
onErrorHandler: errorHandler,
|
||||||
onTurnDone: () => this.tick()
|
onTurnDone: () => this.tick()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +1,68 @@
|
||||||
library angular.zone;
|
library angular.zone;
|
||||||
|
|
||||||
import 'dart:async' as async;
|
import 'dart:async' as async;
|
||||||
|
import 'package:stack_trace/stack_trace.dart' show Chain;
|
||||||
|
|
||||||
class VmTurnZone {
|
class VmTurnZone {
|
||||||
Function _onTurnStart;
|
Function _onTurnStart;
|
||||||
Function _onTurnDone;
|
Function _onTurnDone;
|
||||||
Function _onScheduleMicrotask;
|
Function _onScheduleMicrotask;
|
||||||
|
Function _onErrorHandler;
|
||||||
|
|
||||||
async.Zone _outerZone;
|
async.Zone _outerZone;
|
||||||
async.Zone _innerZone;
|
async.Zone _innerZone;
|
||||||
|
|
||||||
int _nestedRunCounter;
|
int _nestedRunCounter;
|
||||||
|
|
||||||
VmTurnZone() {
|
VmTurnZone({bool enableLongStackTrace}) {
|
||||||
_nestedRunCounter = 0;
|
_nestedRunCounter = 0;
|
||||||
_outerZone = async.Zone.current;
|
_outerZone = async.Zone.current;
|
||||||
_innerZone = _outerZone.fork(specification: new async.ZoneSpecification(
|
_innerZone = _createInnerZoneWithErrorHandling(enableLongStackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
initCallbacks({Function onTurnStart, Function onTurnDone, Function onScheduleMicrotask, Function onErrorHandler}) {
|
||||||
|
this._onTurnStart = onTurnStart;
|
||||||
|
this._onTurnDone = onTurnDone;
|
||||||
|
this._onScheduleMicrotask = onScheduleMicrotask;
|
||||||
|
this._onErrorHandler = onErrorHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic run(fn()) => _innerZone.run(fn);
|
||||||
|
|
||||||
|
dynamic runOutsideAngular(fn()) => _outerZone.run(fn);
|
||||||
|
|
||||||
|
|
||||||
|
async.Zone _createInnerZoneWithErrorHandling(bool enableLongStackTrace) {
|
||||||
|
if (enableLongStackTrace) {
|
||||||
|
return Chain.capture(() {
|
||||||
|
return _createInnerZone(async.Zone.current);
|
||||||
|
}, onError: this._onErrorWithLongStackTrace);
|
||||||
|
} else {
|
||||||
|
return async.runZoned(() {
|
||||||
|
return _createInnerZone(async.Zone.current);
|
||||||
|
}, onError: this._onErrorWithoutLongStackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async.Zone _createInnerZone(async.Zone zone) {
|
||||||
|
return zone.fork(specification: new async.ZoneSpecification(
|
||||||
run: _onRun,
|
run: _onRun,
|
||||||
runUnary: _onRunUnary,
|
runUnary: _onRunUnary,
|
||||||
scheduleMicrotask: _onMicrotask
|
scheduleMicrotask: _onMicrotask
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
initCallbacks({Function onTurnStart, Function onTurnDone, Function onScheduleMicrotask}) {
|
|
||||||
this._onTurnStart = onTurnStart;
|
|
||||||
this._onTurnDone = onTurnDone;
|
|
||||||
this._onScheduleMicrotask = onScheduleMicrotask;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic run(fn()) => _innerZone.run(fn);
|
|
||||||
|
|
||||||
dynamic runOutsideAngular(fn()) => _outerZone.run(fn);
|
|
||||||
|
|
||||||
|
|
||||||
dynamic _onRunBase(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn()) {
|
dynamic _onRunBase(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn()) {
|
||||||
_nestedRunCounter++;
|
_nestedRunCounter++;
|
||||||
try {
|
try {
|
||||||
if (_nestedRunCounter == 1 && _onTurnStart != null) delegate.run(zone, _onTurnStart);
|
if (_nestedRunCounter == 1 && _onTurnStart != null) delegate.run(zone, _onTurnStart);
|
||||||
|
|
||||||
return fn();
|
return fn();
|
||||||
|
} catch (e, s) {
|
||||||
|
if (_onErrorHandler != null && _nestedRunCounter == 1) {
|
||||||
|
_onErrorHandler(e, [s.toString()]);
|
||||||
|
} else {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
_nestedRunCounter--;
|
_nestedRunCounter--;
|
||||||
if (_nestedRunCounter == 0 && _onTurnDone != null) _finishTurn(zone, delegate);
|
if (_nestedRunCounter == 0 && _onTurnDone != null) _finishTurn(zone, delegate);
|
||||||
|
@ -47,10 +70,10 @@ class VmTurnZone {
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic _onRun(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn()) =>
|
dynamic _onRun(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn()) =>
|
||||||
_onRunBase(self, delegate, zone, () => delegate.run(zone, fn));
|
_onRunBase(self, delegate, zone, () => delegate.run(zone, fn));
|
||||||
|
|
||||||
dynamic _onRunUnary(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn(args), args) =>
|
dynamic _onRunUnary(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn(args), args) =>
|
||||||
_onRunBase(self, delegate, zone, () => delegate.runUnary(zone, fn, args));
|
_onRunBase(self, delegate, zone, () => delegate.runUnary(zone, fn, args));
|
||||||
|
|
||||||
void _finishTurn(zone, delegate) {
|
void _finishTurn(zone, delegate) {
|
||||||
delegate.run(zone, _onTurnDone);
|
delegate.run(zone, _onTurnDone);
|
||||||
|
@ -58,9 +81,25 @@ class VmTurnZone {
|
||||||
|
|
||||||
_onMicrotask(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn) {
|
_onMicrotask(async.Zone self, async.ZoneDelegate delegate, async.Zone zone, fn) {
|
||||||
if (this._onScheduleMicrotask != null) {
|
if (this._onScheduleMicrotask != null) {
|
||||||
this._onScheduleMicrotask(fn);
|
_onScheduleMicrotask(fn);
|
||||||
} else {
|
} else {
|
||||||
delegate.scheduleMicrotask(zone, fn);
|
delegate.scheduleMicrotask(zone, fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onErrorWithLongStackTrace(exception, Chain chain) {
|
||||||
|
final traces = chain.terse.traces.map((t) => t.toString()).toList();
|
||||||
|
_onError(exception, traces, chain.traces[0]);
|
||||||
|
}
|
||||||
|
_onErrorWithoutLongStackTrace(exception, StackTrace trace) {
|
||||||
|
_onError(exception, [trace.toString()], trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onError(exception, List<String> traces, StackTrace singleTrace) {
|
||||||
|
if (_onErrorHandler != null) {
|
||||||
|
_onErrorHandler(exception, traces);
|
||||||
|
} else {
|
||||||
|
_outerZone.handleUncaughtError(exception, singleTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {List, ListWrapper} from 'facade/collection';
|
import {List, ListWrapper, StringMapWrapper} from 'facade/collection';
|
||||||
import {normalizeBlank} from 'facade/lang';
|
import {normalizeBlank, isPresent} from 'facade/lang';
|
||||||
|
|
||||||
export class VmTurnZone {
|
export class VmTurnZone {
|
||||||
_outerZone;
|
_outerZone;
|
||||||
|
@ -7,24 +7,24 @@ export class VmTurnZone {
|
||||||
|
|
||||||
_onTurnStart:Function;
|
_onTurnStart:Function;
|
||||||
_onTurnDone:Function;
|
_onTurnDone:Function;
|
||||||
|
_onErrorHandler:Function;
|
||||||
|
|
||||||
_nestedRunCounter:number;
|
_nestedRunCounter:number;
|
||||||
|
|
||||||
constructor() {
|
constructor({enableLongStackTrace}) {
|
||||||
this._nestedRunCounter = 0;
|
this._nestedRunCounter = 0;
|
||||||
this._onTurnStart = null;
|
this._onTurnStart = null;
|
||||||
this._onTurnDone = null;
|
this._onTurnDone = null;
|
||||||
|
this._onErrorHandler = null;
|
||||||
|
|
||||||
this._outerZone = window.zone;
|
this._outerZone = window.zone;
|
||||||
this._innerZone = this._outerZone.fork({
|
this._innerZone = this._createInnerZone(this._outerZone, enableLongStackTrace);
|
||||||
beforeTask: () => this._beforeTask(),
|
|
||||||
afterTask: () => this._afterTask()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initCallbacks({onTurnStart, onTurnDone, onScheduleMicrotask} = {}) {
|
initCallbacks({onTurnStart, onTurnDone, onScheduleMicrotask, onErrorHandler} = {}) {
|
||||||
this._onTurnStart = normalizeBlank(onTurnStart);
|
this._onTurnStart = normalizeBlank(onTurnStart);
|
||||||
this._onTurnDone = normalizeBlank(onTurnDone);
|
this._onTurnDone = normalizeBlank(onTurnDone);
|
||||||
|
this._onErrorHandler = normalizeBlank(onErrorHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
run(fn) {
|
run(fn) {
|
||||||
|
@ -35,6 +35,29 @@ export class VmTurnZone {
|
||||||
return this._outerZone.run(fn);
|
return this._outerZone.run(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_createInnerZone(zone, enableLongStackTrace) {
|
||||||
|
var vmTurnZone = this;
|
||||||
|
var errorHandling;
|
||||||
|
|
||||||
|
if (enableLongStackTrace) {
|
||||||
|
errorHandling = StringMapWrapper.merge(Zone.longStackTraceZone, {
|
||||||
|
onError: function (e) {
|
||||||
|
vmTurnZone._onError(this, e)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
errorHandling = {
|
||||||
|
onError: function (e) {
|
||||||
|
vmTurnZone._onError(this, e)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return zone.fork(errorHandling).fork({
|
||||||
|
beforeTask: () => {this._beforeTask()},
|
||||||
|
afterTask: () => {this._afterTask()}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
_beforeTask(){
|
_beforeTask(){
|
||||||
this._nestedRunCounter ++;
|
this._nestedRunCounter ++;
|
||||||
|
@ -49,4 +72,18 @@ export class VmTurnZone {
|
||||||
this._onTurnDone();
|
this._onTurnDone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onError(zone, e) {
|
||||||
|
if (isPresent(this._onErrorHandler)) {
|
||||||
|
var trace = [normalizeBlank(e.stack)];
|
||||||
|
|
||||||
|
while (zone && zone.constructedAtException) {
|
||||||
|
trace.push(zone.constructedAtException.get());
|
||||||
|
zone = zone.parent;
|
||||||
|
}
|
||||||
|
this._onErrorHandler(e, trace);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -54,7 +54,7 @@ export function main() {
|
||||||
|
|
||||||
describe('bootstrap factory method', () => {
|
describe('bootstrap factory method', () => {
|
||||||
it('should throw if no element is found', (done) => {
|
it('should throw if no element is found', (done) => {
|
||||||
var injectorPromise = bootstrap(HelloRootCmp);
|
var injectorPromise = bootstrap(HelloRootCmp, [], (e,t) => {throw e;});
|
||||||
PromiseWrapper.then(injectorPromise, null, (reason) => {
|
PromiseWrapper.then(injectorPromise, null, (reason) => {
|
||||||
expect(reason.message).toContain(
|
expect(reason.message).toContain(
|
||||||
'The app selector "hello-app" did not match any elements');
|
'The app selector "hello-app" did not match any elements');
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
../packages
|
|
@ -10,7 +10,7 @@ export function main() {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
log = new Log();
|
log = new Log();
|
||||||
zone = new VmTurnZone();
|
zone = new VmTurnZone({enableLongStackTrace: true});
|
||||||
zone.initCallbacks({
|
zone.initCallbacks({
|
||||||
onTurnStart: log.fn('onTurnStart'),
|
onTurnStart: log.fn('onTurnStart'),
|
||||||
onTurnDone: log.fn('onTurnDone')
|
onTurnDone: log.fn('onTurnDone')
|
||||||
|
@ -73,12 +73,95 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("exceptions", () => {
|
describe("exceptions", () => {
|
||||||
it('should rethrow exceptions from the body', () => {
|
var trace, exception, saveStackTrace;
|
||||||
|
beforeEach(() => {
|
||||||
|
trace = null;
|
||||||
|
exception = null;
|
||||||
|
saveStackTrace = (e, t) => {
|
||||||
|
exception = e;
|
||||||
|
trace = t;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call the on error callback when it is defined', () => {
|
||||||
|
zone.initCallbacks({onErrorHandler: saveStackTrace});
|
||||||
|
|
||||||
|
zone.run(() => {
|
||||||
|
throw new BaseException('aaa');
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(exception).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rethrow exceptions from the body when no callback defined', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
zone.run(() => {
|
zone.run(() => {
|
||||||
throw new BaseException('hello');
|
throw new BaseException('bbb');
|
||||||
});
|
});
|
||||||
}).toThrowError('hello');
|
}).toThrowError('bbb');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should produce long stack traces', (done) => {
|
||||||
|
zone.initCallbacks({onErrorHandler: saveStackTrace});
|
||||||
|
|
||||||
|
var c = PromiseWrapper.completer();
|
||||||
|
|
||||||
|
zone.run(function () {
|
||||||
|
PromiseWrapper.setTimeout(function () {
|
||||||
|
PromiseWrapper.setTimeout(function () {
|
||||||
|
c.complete(null);
|
||||||
|
throw new BaseException('ccc');
|
||||||
|
}, 0);
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
c.promise.then((_) => {
|
||||||
|
// then number of traces for JS and Dart is different
|
||||||
|
expect(trace.length).toBeGreaterThan(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should produce long stack traces (when using promises)', (done) => {
|
||||||
|
zone.initCallbacks({onErrorHandler: saveStackTrace});
|
||||||
|
|
||||||
|
var c = PromiseWrapper.completer();
|
||||||
|
|
||||||
|
zone.run(function () {
|
||||||
|
PromiseWrapper.resolve(null).then((_) => {
|
||||||
|
return PromiseWrapper.resolve(null).then((__) => {
|
||||||
|
c.complete(null);
|
||||||
|
throw new BaseException("ddd");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
c.promise.then((_) => {
|
||||||
|
// then number of traces for JS and Dart is different
|
||||||
|
expect(trace.length).toBeGreaterThan(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disable long stack traces', (done) => {
|
||||||
|
var zone = new VmTurnZone({enableLongStackTrace: false});
|
||||||
|
zone.initCallbacks({onErrorHandler: saveStackTrace});
|
||||||
|
|
||||||
|
var c = PromiseWrapper.completer();
|
||||||
|
|
||||||
|
zone.run(function () {
|
||||||
|
PromiseWrapper.setTimeout(function () {
|
||||||
|
PromiseWrapper.setTimeout(function () {
|
||||||
|
c.complete(null);
|
||||||
|
throw new BaseException('ccc');
|
||||||
|
}, 0);
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
c.promise.then((_) => {
|
||||||
|
expect(trace.length).toEqual(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,11 +12,11 @@ class PromiseWrapper {
|
||||||
return new Future.error(obj);
|
return new Future.error(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<List> all(List<Future> promises){
|
static Future<List> all(List<Future> promises) {
|
||||||
return Future.wait(promises);
|
return Future.wait(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future then(Future promise, Function success, Function onError){
|
static Future then(Future promise, Function success, Function onError) {
|
||||||
if (success == null) return promise.catchError(onError);
|
if (success == null) return promise.catchError(onError);
|
||||||
return promise.then(success, onError: onError);
|
return promise.then(success, onError: onError);
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,24 @@ class PromiseWrapper {
|
||||||
static completer(){
|
static completer(){
|
||||||
return new _Completer(new Completer());
|
return new _Completer(new Completer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static setTimeout(fn, millis) {
|
||||||
|
new Timer(new Duration(milliseconds: millis), fn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Completer {
|
class _Completer {
|
||||||
Completer c;
|
Completer c;
|
||||||
|
|
||||||
_Completer(this.c);
|
_Completer(this.c);
|
||||||
|
|
||||||
get promise => c.future;
|
get promise => c.future;
|
||||||
get complete => c.complete;
|
|
||||||
get reject => c.completeError;
|
complete(v) {
|
||||||
|
c.complete(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
reject(v) {
|
||||||
|
c.completeError(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,4 +33,8 @@ export class PromiseWrapper {
|
||||||
reject: reject
|
reject: reject
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static setTimeout(fn, millis) {
|
||||||
|
window.setTimeout(fn, millis);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -59,6 +59,24 @@ export class StringMapWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static merge(m1, m2) {
|
||||||
|
var m = {};
|
||||||
|
|
||||||
|
for (var attr in m1) {
|
||||||
|
if (m1.hasOwnProperty(attr)){
|
||||||
|
m[attr] = m1[attr];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var attr in m2) {
|
||||||
|
if (m2.hasOwnProperty(attr)){
|
||||||
|
m[attr] = m2[attr];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ListWrapper {
|
export class ListWrapper {
|
||||||
|
|
|
@ -214,4 +214,8 @@ export function assertionsEnabled() {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function print(obj) {
|
||||||
|
console.log(obj);
|
||||||
}
|
}
|
Loading…
Reference in New Issue