refactor(change_detection): made ChangeDetector and ProtoChangeDetector interfaces

List of changes:

- Makes ChangeDetector and ProtoChangeDetector interfaces
- Assigns a unique id to every detector
This commit is contained in:
vsavkin
2015-06-18 14:47:38 -07:00
parent ee8da36d08
commit f80f97253c
20 changed files with 134 additions and 93 deletions

View File

@ -25,8 +25,8 @@ export {
} from './src/change_detection/exceptions'; } from './src/change_detection/exceptions';
export { export {
ProtoChangeDetector, ProtoChangeDetector,
ChangeDispatcher,
ChangeDetector, ChangeDetector,
ChangeDispatcher,
ChangeDetection, ChangeDetection,
ChangeDetectorDefinition ChangeDetectorDefinition
} from './src/change_detection/interfaces'; } from './src/change_detection/interfaces';

View File

@ -2,19 +2,17 @@ import {isPresent} from 'angular2/src/facade/lang';
import {List, ListWrapper} from 'angular2/src/facade/collection'; import {List, ListWrapper} from 'angular2/src/facade/collection';
import {ChangeDetectorRef} from './change_detector_ref'; import {ChangeDetectorRef} from './change_detector_ref';
import {ChangeDetector} from './interfaces'; import {ChangeDetector} from './interfaces';
import {Locals} from './parser/locals';
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants'; import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
export class AbstractChangeDetector extends ChangeDetector { export class AbstractChangeDetector implements ChangeDetector {
lightDomChildren: List<any> = []; lightDomChildren: List<any> = [];
shadowDomChildren: List<any> = []; shadowDomChildren: List<any> = [];
parent: ChangeDetector; parent: ChangeDetector;
mode: string = null; mode: string = null;
ref: ChangeDetectorRef; ref: ChangeDetectorRef;
constructor() { constructor(public id: string) { this.ref = new ChangeDetectorRef(this); }
super();
this.ref = new ChangeDetectorRef(this);
}
addChild(cd: ChangeDetector): void { addChild(cd: ChangeDetector): void {
this.lightDomChildren.push(cd); this.lightDomChildren.push(cd);
@ -51,6 +49,11 @@ export class AbstractChangeDetector extends ChangeDetector {
} }
detectChangesInRecords(throwOnChange: boolean): void {} detectChangesInRecords(throwOnChange: boolean): void {}
hydrate(context: any, locals: Locals, directives: any): void {}
dehydrate(): void {}
callOnAllChangesDone(): void {} callOnAllChangesDone(): void {}
_detectChangesInLightDomChildren(throwOnChange: boolean): void { _detectChangesInLightDomChildren(throwOnChange: boolean): void {

View File

@ -38,7 +38,7 @@ export class ChangeDetectorJITGenerator {
_fieldNames: List<string>; _fieldNames: List<string>;
_pipeNames: List<string>; _pipeNames: List<string>;
constructor(public typeName: string, public changeDetectionStrategy: string, constructor(public id: string, public changeDetectionStrategy: string,
public records: List<ProtoRecord>, public directiveRecords: List<any>) { public records: List<ProtoRecord>, public directiveRecords: List<any>) {
this._localNames = this._getLocalNames(records); this._localNames = this._getLocalNames(records);
this._changeNames = this._getChangeNames(this._localNames); this._changeNames = this._getChangeNames(this._localNames);
@ -48,10 +48,7 @@ export class ChangeDetectorJITGenerator {
_getLocalNames(records: List<ProtoRecord>): List<string> { _getLocalNames(records: List<ProtoRecord>): List<string> {
var index = 0; var index = 0;
var names = records.map((r) => { var names = records.map((r) => { return _sanitizeName(`${r.name}${index++}`); });
var sanitizedName = r.name.replace(new RegExp("\\W", "g"), '');
return `${sanitizedName}${index++}`
});
return ["context"].concat(names); return ["context"].concat(names);
} }
@ -68,9 +65,10 @@ export class ChangeDetectorJITGenerator {
} }
generate(): Function { generate(): Function {
var typeName = _sanitizeName(`ChangeDetector_${this.id}`);
var classDefinition = ` var classDefinition = `
var ${this.typeName} = function ${this.typeName}(dispatcher, pipeRegistry, protos, directiveRecords) { var ${typeName} = function ${typeName}(dispatcher, pipeRegistry, protos, directiveRecords) {
${ABSTRACT_CHANGE_DETECTOR}.call(this); ${ABSTRACT_CHANGE_DETECTOR}.call(this, ${JSON.stringify(this.id)});
${DISPATCHER_ACCESSOR} = dispatcher; ${DISPATCHER_ACCESSOR} = dispatcher;
${PIPE_REGISTRY_ACCESSOR} = pipeRegistry; ${PIPE_REGISTRY_ACCESSOR} = pipeRegistry;
${PROTOS_ACCESSOR} = protos; ${PROTOS_ACCESSOR} = protos;
@ -80,9 +78,9 @@ export class ChangeDetectorJITGenerator {
${this._genFieldDefinitions()} ${this._genFieldDefinitions()}
} }
${this.typeName}.prototype = Object.create(${ABSTRACT_CHANGE_DETECTOR}.prototype); ${typeName}.prototype = Object.create(${ABSTRACT_CHANGE_DETECTOR}.prototype);
${this.typeName}.prototype.detectChangesInRecords = function(throwOnChange) { ${typeName}.prototype.detectChangesInRecords = function(throwOnChange) {
if (!this.hydrated()) { if (!this.hydrated()) {
${UTIL}.throwDehydrated(); ${UTIL}.throwDehydrated();
} }
@ -99,11 +97,11 @@ export class ChangeDetectorJITGenerator {
${ALREADY_CHECKED_ACCESSOR} = true; ${ALREADY_CHECKED_ACCESSOR} = true;
} }
${this.typeName}.prototype.callOnAllChangesDone = function() { ${typeName}.prototype.callOnAllChangesDone = function() {
${this._genCallOnAllChangesDoneBody()} ${this._genCallOnAllChangesDoneBody()}
} }
${this.typeName}.prototype.hydrate = function(context, locals, directives) { ${typeName}.prototype.hydrate = function(context, locals, directives) {
${MODE_ACCESSOR} = "${ChangeDetectionUtil.changeDetectionMode(this.changeDetectionStrategy)}"; ${MODE_ACCESSOR} = "${ChangeDetectionUtil.changeDetectionMode(this.changeDetectionStrategy)}";
${CONTEXT_ACCESSOR} = context; ${CONTEXT_ACCESSOR} = context;
${LOCALS_ACCESSOR} = locals; ${LOCALS_ACCESSOR} = locals;
@ -112,21 +110,20 @@ export class ChangeDetectorJITGenerator {
${ALREADY_CHECKED_ACCESSOR} = false; ${ALREADY_CHECKED_ACCESSOR} = false;
} }
${this.typeName}.prototype.dehydrate = function() { ${typeName}.prototype.dehydrate = function() {
${this._genPipeOnDestroy()} ${this._genPipeOnDestroy()}
${this._genFieldDefinitions()} ${this._genFieldDefinitions()}
${LOCALS_ACCESSOR} = null; ${LOCALS_ACCESSOR} = null;
} }
${this.typeName}.prototype.hydrated = function() { ${typeName}.prototype.hydrated = function() {
return ${CONTEXT_ACCESSOR} !== null; return ${CONTEXT_ACCESSOR} !== null;
} }
return function(dispatcher, pipeRegistry) { return function(dispatcher, pipeRegistry) {
return new ${this.typeName}(dispatcher, pipeRegistry, protos, directiveRecords); return new ${typeName}(dispatcher, pipeRegistry, protos, directiveRecords);
} }
`; `;
return new Function('AbstractChangeDetector', 'ChangeDetectionUtil', 'protos', return new Function('AbstractChangeDetector', 'ChangeDetectionUtil', 'protos',
'directiveRecords', classDefinition)( 'directiveRecords', classDefinition)(
AbstractChangeDetector, ChangeDetectionUtil, this.records, this.directiveRecords); AbstractChangeDetector, ChangeDetectionUtil, this.records, this.directiveRecords);
@ -444,3 +441,7 @@ export class ChangeDetectorJITGenerator {
return retVal; return retVal;
} }
} }
function _sanitizeName(s: string): string {
return s.replace(new RegExp("\\W", "g"), '');
}

View File

@ -21,10 +21,10 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
directives: any = null; directives: any = null;
alreadyChecked: boolean = false; alreadyChecked: boolean = false;
constructor(private changeControlStrategy: string, private dispatcher: any, constructor(id: string, private changeControlStrategy: string, private dispatcher: any,
private pipeRegistry: PipeRegistry, private protos: List<ProtoRecord>, private pipeRegistry: PipeRegistry, private protos: List<ProtoRecord>,
private directiveRecords: List<any>) { private directiveRecords: List<any>) {
super(); super(id);
this.values = ListWrapper.createFixedSize(protos.length + 1); this.values = ListWrapper.createFixedSize(protos.length + 1);
this.pipes = ListWrapper.createFixedSize(protos.length + 1); this.pipes = ListWrapper.createFixedSize(protos.length + 1);
this.prevContexts = ListWrapper.createFixedSize(protos.length + 1); this.prevContexts = ListWrapper.createFixedSize(protos.length + 1);

View File

@ -3,10 +3,6 @@ import {Locals} from './parser/locals';
import {BindingRecord} from './binding_record'; import {BindingRecord} from './binding_record';
import {DirectiveRecord} from './directive_record'; import {DirectiveRecord} from './directive_record';
export class ProtoChangeDetector {
instantiate(dispatcher: any): ChangeDetector { return null; }
}
/** /**
* Interface used by Angular to control the change detection strategy for an application. * Interface used by Angular to control the change detection strategy for an application.
* *
@ -39,27 +35,30 @@ export class ChangeDetection {
} }
} }
export class ChangeDispatcher { export interface ChangeDispatcher {
notifyOnBinding(bindingRecord: BindingRecord, value: any) {} notifyOnBinding(bindingRecord: BindingRecord, value: any): void;
notifyOnAllChangesDone(): void;
} }
export class ChangeDetector { export interface ChangeDetector {
parent: ChangeDetector; parent: ChangeDetector;
mode: string; mode: string;
addChild(cd: ChangeDetector): void {} addChild(cd: ChangeDetector): void;
addShadowDomChild(cd: ChangeDetector): void {} addShadowDomChild(cd: ChangeDetector): void;
removeChild(cd: ChangeDetector): void {} removeChild(cd: ChangeDetector): void;
removeShadowDomChild(cd: ChangeDetector): void {} removeShadowDomChild(cd: ChangeDetector): void;
remove(): void {} remove(): void;
hydrate(context: any, locals: Locals, directives: any): void {} hydrate(context: any, locals: Locals, directives: any): void;
dehydrate(): void {} dehydrate(): void;
markPathToRootAsCheckOnce(): void {} markPathToRootAsCheckOnce(): void;
detectChanges(): void {} detectChanges(): void;
checkNoChanges(): void {} checkNoChanges(): void;
} }
export interface ProtoChangeDetector { instantiate(dispatcher: any): ChangeDetector; }
export class ChangeDetectorDefinition { export class ChangeDetectorDefinition {
constructor(public id: string, public strategy: string, public variableNames: List<string>, constructor(public id: string, public strategy: string, public variableNames: List<string>,
public bindingRecords: List<BindingRecord>, public bindingRecords: List<BindingRecord>,

View File

@ -6,12 +6,10 @@ import {ChangeDetectorJITGenerator} from './change_detection_jit_generator';
import {coalesce} from './coalesce'; import {coalesce} from './coalesce';
import {ProtoRecordBuilder} from './proto_change_detector'; import {ProtoRecordBuilder} from './proto_change_detector';
var _jitProtoChangeDetectorClassCounter: number = 0; export class JitProtoChangeDetector implements ProtoChangeDetector {
export class JitProtoChangeDetector extends ProtoChangeDetector {
_factory: Function; _factory: Function;
constructor(private _pipeRegistry, private definition: ChangeDetectorDefinition) { constructor(private _pipeRegistry, private definition: ChangeDetectorDefinition) {
super();
this._factory = this._createFactory(definition); this._factory = this._createFactory(definition);
} }
@ -25,10 +23,8 @@ export class JitProtoChangeDetector extends ProtoChangeDetector {
var recordBuilder = new ProtoRecordBuilder(); var recordBuilder = new ProtoRecordBuilder();
ListWrapper.forEach(definition.bindingRecords, ListWrapper.forEach(definition.bindingRecords,
(b) => { recordBuilder.add(b, definition.variableNames); }); (b) => { recordBuilder.add(b, definition.variableNames); });
var c = _jitProtoChangeDetectorClassCounter++;
var records = coalesce(recordBuilder.records); var records = coalesce(recordBuilder.records);
var typeName = `ChangeDetector${c}`; return new ChangeDetectorJITGenerator(definition.id, definition.strategy, records,
return new ChangeDetectorJITGenerator(typeName, definition.strategy, records,
this.definition.directiveRecords) this.definition.directiveRecords)
.generate(); .generate();
} }

View File

@ -5,7 +5,7 @@ import {coalesce} from './coalesce';
export {Function as PregenProtoChangeDetectorFactory}; export {Function as PregenProtoChangeDetectorFactory};
export class PregenProtoChangeDetector extends ProtoChangeDetector { export class PregenProtoChangeDetector implements ProtoChangeDetector {
static isSupported(): boolean { return false; } static isSupported(): boolean { return false; }
instantiate(dispatcher: any): ChangeDetector { instantiate(dispatcher: any): ChangeDetector {

View File

@ -25,12 +25,7 @@ import {
SafeMethodCall SafeMethodCall
} from './parser/ast'; } from './parser/ast';
import { import {ChangeDetector, ProtoChangeDetector, ChangeDetectorDefinition} from './interfaces';
ChangeDispatcher,
ChangeDetector,
ProtoChangeDetector,
ChangeDetectorDefinition
} from './interfaces';
import {ChangeDetectionUtil} from './change_detection_util'; import {ChangeDetectionUtil} from './change_detection_util';
import {DynamicChangeDetector} from './dynamic_change_detector'; import {DynamicChangeDetector} from './dynamic_change_detector';
import {PipeRegistry} from './pipes/pipe_registry'; import {PipeRegistry} from './pipes/pipe_registry';
@ -41,17 +36,17 @@ import {coalesce} from './coalesce';
import {ProtoRecord, RecordType} from './proto_record'; import {ProtoRecord, RecordType} from './proto_record';
export class DynamicProtoChangeDetector extends ProtoChangeDetector { export class DynamicProtoChangeDetector implements ProtoChangeDetector {
_records: List<ProtoRecord>; _records: List<ProtoRecord>;
constructor(private _pipeRegistry: PipeRegistry, private definition: ChangeDetectorDefinition) { constructor(private _pipeRegistry: PipeRegistry, private definition: ChangeDetectorDefinition) {
super();
this._records = this._createRecords(definition); this._records = this._createRecords(definition);
} }
instantiate(dispatcher: any) { instantiate(dispatcher: any) {
return new DynamicChangeDetector(this.definition.strategy, dispatcher, this._pipeRegistry, return new DynamicChangeDetector(this.definition.id, this.definition.strategy, dispatcher,
this._records, this.definition.directiveRecords); this._pipeRegistry, this._records,
this.definition.directiveRecords);
} }
_createRecords(definition: ChangeDetectorDefinition) { _createRecords(definition: ChangeDetectorDefinition) {

View File

@ -0,0 +1,47 @@
import {
ChangeDetector,
ProtoChangeDetector,
DynamicChangeDetector
} from 'angular2/change_detection';
import {SpyObject, proxy} from './test_lib';
// Remove dummy methods after https://github.com/angular/ts2dart/issues/209 is fixed.
@proxy
export class SpyChangeDetector extends SpyObject implements ChangeDetector {
parent: ChangeDetector;
mode: string;
constructor() { super(DynamicChangeDetector, true); }
addChild(cd: ChangeDetector): void { return this.spy("addChild")(cd); }
addShadowDomChild(cd: ChangeDetector): void { return this.spy("addShadowDomChild")(cd); }
removeChild(cd: ChangeDetector): void { return this.spy("removeChild")(cd); }
removeShadowDomChild(cd: ChangeDetector): void { return this.spy("removeShadowDomChild")(cd); }
remove(): void { return this.spy("remove")(); }
hydrate(context: any, locals: any, directives: any): void {
return this.spy("hydrate")(context, locals, directives);
}
dehydrate(): void { return this.spy("dehydrate")(); }
markPathToRootAsCheckOnce(): void { return this.spy("markPathToRootAsCheckOnce")(); }
detectChanges(): void { return this.spy("detectChanges")(); }
checkNoChanges(): void { return this.spy("checkNoChanges")(); }
noSuchMethod(m) { return super.noSuchMethod(m) }
}
// Remove dummy methods after https://github.com/angular/ts2dart/issues/209 is fixed.
@proxy
export class SpyProtoChangeDetector extends SpyObject implements ProtoChangeDetector {
constructor() { super(DynamicChangeDetector, true); }
instantiate(v: any): any { return this.spy("instantiate")(v); }
}

View File

@ -187,7 +187,7 @@ class SpyFunction extends gns.SpyFunction {
class SpyObject extends gns.SpyObject { class SpyObject extends gns.SpyObject {
final Map<String, SpyFunction> _spyFuncs = {}; final Map<String, SpyFunction> _spyFuncs = {};
SpyObject([arg]) {} SpyObject([arg, arg2]) {}
SpyFunction spy(String funcName) => SpyFunction spy(String funcName) =>
_spyFuncs.putIfAbsent(funcName, () => new SpyFunction(funcName)); _spyFuncs.putIfAbsent(funcName, () => new SpyFunction(funcName));

View File

@ -280,7 +280,7 @@ export interface GuinessCompatibleSpy extends jasmine.Spy {
} }
export class SpyObject { export class SpyObject {
constructor(type = null) { constructor(type = null, forceSpyCreation: boolean = false) {
if (type) { if (type) {
for (var prop in type.prototype) { for (var prop in type.prototype) {
var m = null; var m = null;
@ -293,7 +293,11 @@ export class SpyObject {
// should not matter. // should not matter.
} }
if (typeof m === 'function') { if (typeof m === 'function') {
this.spy(prop); if (forceSpyCreation) {
this.createSpy(prop);
} else {
this.spy(prop);
}
} }
} }
} }
@ -303,8 +307,14 @@ export class SpyObject {
spy(name) { spy(name) {
if (!this[name]) { if (!this[name]) {
this[name] = this._createGuinnessCompatibleSpy(name); return this.createSpy(name);
} else {
return this[name];
} }
}
createSpy(name) {
this[name] = this._createGuinnessCompatibleSpy(name);
return this[name]; return this[name];
} }

View File

@ -142,7 +142,7 @@ class _CodegenState {
this.$_DISPATCHER_ACCESSOR, this.$_DISPATCHER_ACCESSOR,
this.$_PIPE_REGISTRY_ACCESSOR, this.$_PIPE_REGISTRY_ACCESSOR,
this.$_PROTOS_ACCESSOR, this.$_PROTOS_ACCESSOR,
this.$_DIRECTIVES_ACCESSOR) : super(); this.$_DIRECTIVES_ACCESSOR) : super(${JSON.encode(_changeDetectorDefId)});
void detectChangesInRecords(throwOnChange) { void detectChangesInRecords(throwOnChange) {
if (!hydrated()) { if (!hydrated()) {

View File

@ -1,21 +1,28 @@
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib'; import {
ddescribe,
describe,
it,
iit,
xit,
expect,
beforeEach,
afterEach,
SpyProtoChangeDetector
} from 'angular2/test_lib';
import { import {
PreGeneratedChangeDetection, PreGeneratedChangeDetection,
ChangeDetectorDefinition, ChangeDetectorDefinition,
ProtoChangeDetector,
DynamicProtoChangeDetector DynamicProtoChangeDetector
} from 'angular2/change_detection'; } from 'angular2/change_detection';
class DummyChangeDetector extends ProtoChangeDetector {}
export function main() { export function main() {
describe("PreGeneratedChangeDetection", () => { describe("PreGeneratedChangeDetection", () => {
var proto; var proto;
var def; var def;
beforeEach(() => { beforeEach(() => {
proto = new DummyChangeDetector(); proto = new SpyProtoChangeDetector();
def = new ChangeDetectorDefinition('id', null, [], [], []); def = new ChangeDetectorDefinition('id', null, [], [], []);
}); });

View File

@ -990,15 +990,12 @@ class FakeDirectives {
getDetectorFor(di: DirectiveIndex) { return this.detectors[di.directiveIndex]; } getDetectorFor(di: DirectiveIndex) { return this.detectors[di.directiveIndex]; }
} }
class TestDispatcher extends ChangeDispatcher { class TestDispatcher implements ChangeDispatcher {
log: List<string>; log: List<string>;
loggedValues: List<any>; loggedValues: List<any>;
onAllChangesDoneCalled: boolean = false; onAllChangesDoneCalled: boolean = false;
constructor() { constructor() { this.clear(); }
super();
this.clear();
}
clear() { clear() {
this.log = []; this.log = [];

View File

@ -911,7 +911,7 @@ export function main() {
}); });
it('should inject ChangeDetectorRef', () => { it('should inject ChangeDetectorRef', () => {
var cd = new DynamicChangeDetector(null, null, null, [], []); var cd = new DynamicChangeDetector(null, null, null, null, [], []);
var view = <any>new DummyView(); var view = <any>new DummyView();
var childView = new DummyView(); var childView = new DummyView();
childView.changeDetector = cd; childView.changeDetector = cd;

View File

@ -13,6 +13,7 @@ import {
it, it,
xit, xit,
SpyObject, SpyObject,
SpyChangeDetector,
proxy, proxy,
Log Log
} from 'angular2/test_lib'; } from 'angular2/test_lib';
@ -22,7 +23,6 @@ import {IMPLEMENTS, isBlank, isPresent} from 'angular2/src/facade/lang';
import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {AppProtoView, AppView} from 'angular2/src/core/compiler/view'; import {AppProtoView, AppView} from 'angular2/src/core/compiler/view';
import {ChangeDetector} from 'angular2/change_detection';
import {ElementBinder} from 'angular2/src/core/compiler/element_binder'; import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
import { import {
DirectiveBinding, DirectiveBinding,
@ -279,13 +279,6 @@ class SpyElementInjector extends SpyObject {
noSuchMethod(m) { return super.noSuchMethod(m) } noSuchMethod(m) { return super.noSuchMethod(m) }
} }
@proxy
@IMPLEMENTS(ChangeDetector)
class SpyChangeDetector extends SpyObject {
constructor() { super(ChangeDetector); }
noSuchMethod(m) { return super.noSuchMethod(m) }
}
@proxy @proxy
@IMPLEMENTS(PreBuiltObjects) @IMPLEMENTS(PreBuiltObjects)
class SpyPreBuiltObjects extends SpyObject { class SpyPreBuiltObjects extends SpyObject {

View File

@ -11,26 +11,18 @@ import {
AsyncTestCompleter, AsyncTestCompleter,
fakeAsync, fakeAsync,
tick, tick,
SpyObject,
inject, inject,
proxy SpyChangeDetector,
} from 'angular2/test_lib'; } from 'angular2/test_lib';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {ChangeDetector} from 'angular2/change_detection';
import {IMPLEMENTS} from 'angular2/src/facade/lang'; import {IMPLEMENTS} from 'angular2/src/facade/lang';
@proxy
@IMPLEMENTS(ChangeDetector)
class SpyChangeDetector extends SpyObject {
constructor() { super(ChangeDetector); }
noSuchMethod(m) { return super.noSuchMethod(m) }
}
export function main() { export function main() {
describe("LifeCycle", () => { describe("LifeCycle", () => {
it("should throw when reentering tick", () => { it("should throw when reentering tick", () => {
var cd = <any>new SpyChangeDetector(); var cd = <any>new SpyChangeDetector();
var lc = new LifeCycle(null, cd, false); var lc = new LifeCycle(null, cd, false);
cd.spy("detectChanges").andCallFake(() => lc.tick()); cd.spy("detectChanges").andCallFake(() => lc.tick());
expect(() => lc.tick()).toThrowError("LifeCycle.tick is called recursively"); expect(() => lc.tick()).toThrowError("LifeCycle.tick is called recursively");
}); });

View File

@ -34,7 +34,7 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector {
_MyComponent_ChangeDetector0(this._dispatcher, this._pipeRegistry, _MyComponent_ChangeDetector0(this._dispatcher, this._pipeRegistry,
this._protos, this._directiveRecords) this._protos, this._directiveRecords)
: super(); : super("MyComponent_comp_0");
void detectChangesInRecords(throwOnChange) { void detectChangesInRecords(throwOnChange) {
if (!hydrated()) { if (!hydrated()) {

View File

@ -1,4 +1,5 @@
export * from './src/test_lib/test_lib'; export * from './src/test_lib/test_lib';
export * from './src/test_lib/spies';
export * from './src/test_lib/utils'; export * from './src/test_lib/utils';
export * from './src/test_lib/fake_async'; export * from './src/test_lib/fake_async';
export * from './src/test_lib/test_component_builder'; export * from './src/test_lib/test_component_builder';

View File

@ -379,7 +379,7 @@ class FakeDirectives {
getDirectiveFor(record) { return this.targetObj; } getDirectiveFor(record) { return this.targetObj; }
} }
class DummyDispatcher extends ChangeDispatcher { class DummyDispatcher implements ChangeDispatcher {
notifyOnBinding(bindingRecord, newValue) { throw "Should not be used"; } notifyOnBinding(bindingRecord, newValue) { throw "Should not be used"; }
notifyOnAllChangesDone() {} notifyOnAllChangesDone() {}
} }