fix(change_detection): _throwError should not mask the original exception

This commit is contained in:
vsavkin 2015-09-30 15:28:26 -07:00
parent 5557a5716d
commit cec4b36d9b
5 changed files with 42 additions and 9 deletions

View File

@ -287,11 +287,19 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
} }
private _throwError(exception: any, stack: any): void { private _throwError(exception: any, stack: any): void {
var c = this.dispatcher.getDebugContext(this._currentBinding().elementIndex, null); var error;
var context = isPresent(c) ? new _Context(c.element, c.componentElement, c.context, c.locals, try {
c.injector, this._currentBinding().debug) : var c = this.dispatcher.getDebugContext(this._currentBinding().elementIndex, null);
null; var context = isPresent(c) ? new _Context(c.element, c.componentElement, c.context, c.locals,
throw new ChangeDetectionError(this._currentBinding().debug, exception, stack, context); c.injector, this._currentBinding().debug) :
null;
error = new ChangeDetectionError(this._currentBinding().debug, exception, stack, context);
} catch (e) {
// if an error happens during getting the debug context, we throw a ChangeDetectionError
// without the extra information.
error = new ChangeDetectionError(null, exception, stack, null);
}
throw error;
} }
throwOnChangeError(oldValue: any, newValue: any): void { throwOnChangeError(oldValue: any, newValue: any): void {

View File

@ -254,7 +254,7 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
} catch (e) { } catch (e) {
// TODO: vsavkin log the exception once we have a good way to log errors and warnings // TODO: vsavkin log the exception once we have a good way to log errors and warnings
// if an error happens during getting the debug context, we return an empty map. // if an error happens during getting the debug context, we return null.
return null; return null;
} }
} }

View File

@ -11,6 +11,8 @@ import {
fakeAsync fakeAsync
} from 'angular2/test_lib'; } from 'angular2/test_lib';
import {SpyChangeDispatcher} from '../spies';
import { import {
CONST_EXPR, CONST_EXPR,
isPresent, isPresent,
@ -92,8 +94,8 @@ export function main() {
function _createChangeDetector(expression: string, context = _DEFAULT_CONTEXT, function _createChangeDetector(expression: string, context = _DEFAULT_CONTEXT,
registry = null) { registry = null, dispatcher = null) {
var dispatcher = new TestDispatcher(); if (isBlank(dispatcher)) dispatcher = new TestDispatcher();
var testDef = getDefinition(expression); var testDef = getDefinition(expression);
var protoCd = _getProtoChangeDetector(testDef.cdDef); var protoCd = _getProtoChangeDetector(testDef.cdDef);
var cd = protoCd.instantiate(dispatcher); var cd = protoCd.instantiate(dispatcher);
@ -797,6 +799,22 @@ export function main() {
expect(e.location).toEqual('invalidFn(1) in location'); expect(e.location).toEqual('invalidFn(1) in location');
} }
}); });
it('should handle unexpected errors in the event handler itself', () => {
var throwingDispatcher = new SpyChangeDispatcher();
throwingDispatcher.spy("getDebugContext")
.andCallFake((_, __) => { throw new BaseException('boom'); });
var val =
_createChangeDetector('invalidFn(1)', _DEFAULT_CONTEXT, null, throwingDispatcher);
try {
val.changeDetector.detectChanges();
throw new BaseException('fail');
} catch (e) {
expect(e).toBeAnInstanceOf(ChangeDetectionError);
expect(e.location).toEqual(null);
}
});
}); });
describe('Locals', () => { describe('Locals', () => {
@ -1398,5 +1416,5 @@ class TestDispatcher implements ChangeDispatcher {
} }
class _ChangeDetectorAndDispatcher { class _ChangeDetectorAndDispatcher {
constructor(public changeDetector: any, public dispatcher: TestDispatcher) {} constructor(public changeDetector: any, public dispatcher: any) {}
} }

View File

@ -35,6 +35,11 @@ class SpyProtoChangeDetector extends SpyObject implements ProtoChangeDetector {
noSuchMethod(m) => super.noSuchMethod(m); noSuchMethod(m) => super.noSuchMethod(m);
} }
@proxy
class SpyChangeDispatcher extends SpyObject implements ChangeDispatcher {
noSuchMethod(m) => super.noSuchMethod(m);
}
@proxy @proxy
class SpyIterableDifferFactory extends SpyObject class SpyIterableDifferFactory extends SpyObject
implements IterableDifferFactory { implements IterableDifferFactory {

View File

@ -40,6 +40,8 @@ export class SpyProtoChangeDetector extends SpyObject {
constructor() { super(DynamicChangeDetector); } constructor() { super(DynamicChangeDetector); }
} }
export class SpyChangeDispatcher extends SpyObject {}
export class SpyIterableDifferFactory extends SpyObject {} export class SpyIterableDifferFactory extends SpyObject {}
export class SpyRenderCompiler extends SpyObject { export class SpyRenderCompiler extends SpyObject {