feat(errors): preserve stack traces of user exceptions in Dart
This commit is contained in:
parent
421d8916a6
commit
b6f29b4448
|
@ -6,7 +6,9 @@ export 'dart:async' show Future, Stream, StreamController, StreamSubscription;
|
||||||
class PromiseWrapper {
|
class PromiseWrapper {
|
||||||
static Future resolve(obj) => new Future.value(obj);
|
static Future resolve(obj) => new Future.value(obj);
|
||||||
|
|
||||||
static Future reject(obj) => new Future.error(obj);
|
static Future reject(obj) => new Future.error(
|
||||||
|
obj,
|
||||||
|
obj is Error ? obj.stackTrace : null);
|
||||||
|
|
||||||
static Future<List> all(List<Future> promises) => Future.wait(promises);
|
static Future<List> all(List<Future> promises) => Future.wait(promises);
|
||||||
|
|
||||||
|
@ -98,6 +100,10 @@ class _Completer {
|
||||||
}
|
}
|
||||||
|
|
||||||
void reject(v) {
|
void reject(v) {
|
||||||
c.completeError(v);
|
var stack = null;
|
||||||
|
if (v is Error) {
|
||||||
|
stack = v.stackTrace;
|
||||||
|
}
|
||||||
|
c.completeError(v, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,19 @@ import 'package:angular2/di.dart';
|
||||||
import 'package:angular2/src/test_lib/test_bed.dart';
|
import 'package:angular2/src/test_lib/test_bed.dart';
|
||||||
import 'package:angular2/test_lib.dart';
|
import 'package:angular2/test_lib.dart';
|
||||||
|
|
||||||
|
class MockException implements Error { var message; var stackTrace; }
|
||||||
|
|
||||||
|
void functionThatThrows() {
|
||||||
|
try { throw new MockException(); }
|
||||||
|
catch(e, stack) {
|
||||||
|
// If we lose the stack trace the message will no longer match
|
||||||
|
// the first line in the stack
|
||||||
|
e.message = stack.toString().split('\n')[0];
|
||||||
|
e.stackTrace = stack;
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
describe('TypeLiteral', () {
|
describe('TypeLiteral', () {
|
||||||
it('should publish via injectables',
|
it('should publish via injectables',
|
||||||
|
@ -22,6 +35,21 @@ main() {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Error handling', () {
|
||||||
|
it('should preserve stack traces throws from components',
|
||||||
|
inject([TestBed, AsyncTestCompleter], (tb, async) {
|
||||||
|
tb.overrideView(Dummy, new View(
|
||||||
|
template: '<throwing-component></throwing-component>',
|
||||||
|
directives: [ThrowingComponent]
|
||||||
|
));
|
||||||
|
|
||||||
|
tb.createView(Dummy).catchError((e, stack) {
|
||||||
|
expect(stack.toString().split('\n')[0]).toEqual(e.message);
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component(selector: 'dummy')
|
@Component(selector: 'dummy')
|
||||||
|
@ -43,3 +71,13 @@ class TypeLiteralComponent {
|
||||||
|
|
||||||
TypeLiteralComponent(this.list);
|
TypeLiteralComponent(this.list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'throwing-component'
|
||||||
|
)
|
||||||
|
@View(template: '')
|
||||||
|
class ThrowingComponent {
|
||||||
|
ThrowingComponent() {
|
||||||
|
functionThatThrows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
/// This file contains tests that make sense only in Dart
|
||||||
|
library angular2.test.facade.async_dart_spec;
|
||||||
|
|
||||||
|
import 'package:angular2/test_lib.dart';
|
||||||
|
import 'package:angular2/src/facade/async.dart';
|
||||||
|
|
||||||
|
class MockException implements Error { var message; var stackTrace; }
|
||||||
|
|
||||||
|
void functionThatThrows() {
|
||||||
|
try { throw new MockException(); }
|
||||||
|
catch(e, stack) {
|
||||||
|
// If we lose the stack trace the message will no longer match
|
||||||
|
// the first line in the stack
|
||||||
|
e.message = stack.toString().split('\n')[0];
|
||||||
|
e.stackTrace = stack;
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void functionThatThrowsNonError() {
|
||||||
|
throw 'this is an error';
|
||||||
|
}
|
||||||
|
|
||||||
|
void expectFunctionThatThrowsWithStackTrace(
|
||||||
|
Future future, AsyncTestCompleter async) {
|
||||||
|
PromiseWrapper.catchError(future, (err, StackTrace stack) {
|
||||||
|
expect(stack.toString().split('\n')[0]).toEqual(err.message);
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void expectFunctionThatThrowsWithoutStackTrace(Future future,
|
||||||
|
AsyncTestCompleter async) {
|
||||||
|
PromiseWrapper.catchError(future, (err, StackTrace stack) {
|
||||||
|
expect(stack).toBe(null);
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
describe('Completer', () {
|
||||||
|
|
||||||
|
it('should preserve error stack traces',
|
||||||
|
inject([AsyncTestCompleter], (async) {
|
||||||
|
var c = PromiseWrapper.completer();
|
||||||
|
|
||||||
|
expectFunctionThatThrowsWithStackTrace(c.promise, async);
|
||||||
|
|
||||||
|
try {
|
||||||
|
functionThatThrows();
|
||||||
|
} catch(e) {
|
||||||
|
c.reject(e);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// TODO: We might fix this one day; for now testing it to be explicit
|
||||||
|
it('CANNOT preserve error stack traces for non-Errors',
|
||||||
|
inject([AsyncTestCompleter], (async) {
|
||||||
|
var c = PromiseWrapper.completer();
|
||||||
|
|
||||||
|
expectFunctionThatThrowsWithoutStackTrace(c.promise, async);
|
||||||
|
|
||||||
|
try {
|
||||||
|
functionThatThrowsNonError();
|
||||||
|
} catch(e) {
|
||||||
|
c.reject(e);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('PromiseWrapper', () {
|
||||||
|
|
||||||
|
describe('reject', () {
|
||||||
|
|
||||||
|
it('should preserve error stack traces',
|
||||||
|
inject([AsyncTestCompleter], (async) {
|
||||||
|
try {
|
||||||
|
functionThatThrows();
|
||||||
|
} catch(e) {
|
||||||
|
var rejectedFuture = PromiseWrapper.reject(e);
|
||||||
|
expectFunctionThatThrowsWithStackTrace(rejectedFuture, async);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// TODO: We might fix this one day; for now testing it to be explicit
|
||||||
|
it('CANNOT preserve stack traces for non-Errors',
|
||||||
|
inject([AsyncTestCompleter], (async) {
|
||||||
|
try {
|
||||||
|
functionThatThrowsNonError();
|
||||||
|
} catch(e) {
|
||||||
|
var rejectedFuture = PromiseWrapper.reject(e);
|
||||||
|
expectFunctionThatThrowsWithoutStackTrace(rejectedFuture, async);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue