test(change detect): Port remaining unit tests
Move all remaining unit tests for change detectors to exercise Dart pre-generated change detectors as well as `dynamic` and `JIT` change detectors. See #502
This commit is contained in:
parent
17c6d6a92d
commit
ad95601e3c
|
@ -74,6 +74,14 @@ export function main() {
|
|||
}
|
||||
}
|
||||
|
||||
function _createWithoutHydrate(expression: string) {
|
||||
var dispatcher = new TestDispatcher();
|
||||
var registry = null;
|
||||
var cd = _getProtoChangeDetector(getDefinition(expression).cdDef, registry).instantiate(dispatcher);
|
||||
return new _ChangeDetectorAndDispatcher(cd, dispatcher);
|
||||
}
|
||||
|
||||
|
||||
function _createChangeDetector(expression: string, context = _DEFAULT_CONTEXT,
|
||||
registry = null) {
|
||||
var dispatcher = new TestDispatcher();
|
||||
|
@ -223,17 +231,17 @@ export function main() {
|
|||
expect(_bindSimpleValue('address?.toString()', person)).toEqual(['propName=MTV']);
|
||||
});
|
||||
|
||||
it("should support method calls", () => {
|
||||
it('should support method calls', () => {
|
||||
var person = new Person('Victor');
|
||||
expect(_bindSimpleValue('sayHi("Jim")', person)).toEqual(['propName=Hi, Jim']);
|
||||
});
|
||||
|
||||
it("should support function calls", () => {
|
||||
it('should support function calls', () => {
|
||||
var td = new TestData(() => (a) => a);
|
||||
expect(_bindSimpleValue('a()(99)', td)).toEqual(['propName=99']);
|
||||
});
|
||||
|
||||
it("should support chained method calls", () => {
|
||||
it('should support chained method calls', () => {
|
||||
var person = new Person('Victor');
|
||||
var td = new TestData(person);
|
||||
expect(_bindSimpleValue('a.sayHi("Jim")', td)).toEqual(['propName=Hi, Jim']);
|
||||
|
@ -276,7 +284,14 @@ export function main() {
|
|||
expect(val.dispatcher.loggedValues[0]['z']).toEqual(1);
|
||||
});
|
||||
|
||||
// TODO(kegluneq): Insert it('should support interpolation', ...) testcase.
|
||||
it('should support interpolation', () => {
|
||||
var val = _createChangeDetector('interpolation', new TestData('value'));
|
||||
val.changeDetector.hydrate(new TestData('value'), null, null);
|
||||
|
||||
val.changeDetector.detectChanges();
|
||||
|
||||
expect(val.dispatcher.log).toEqual(['propName=BvalueA']);
|
||||
});
|
||||
|
||||
describe('change notification', () => {
|
||||
describe('simple checks', () => {
|
||||
|
@ -298,10 +313,177 @@ export function main() {
|
|||
});
|
||||
});
|
||||
|
||||
// TODO(kegluneq): Insert describe('change notification', ...) testcases.
|
||||
describe('updating directives', () => {
|
||||
var directive1;
|
||||
var directive2;
|
||||
|
||||
beforeEach(() => {
|
||||
directive1 = new TestDirective();
|
||||
directive2 = new TestDirective();
|
||||
});
|
||||
|
||||
it('should happen directly, without invoking the dispatcher', () => {
|
||||
var val = _createWithoutHydrate('directNoDispatcher');
|
||||
val.changeDetector.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []));
|
||||
val.changeDetector.detectChanges();
|
||||
expect(val.dispatcher.loggedValues).toEqual([]);
|
||||
expect(directive1.a).toEqual(42);
|
||||
});
|
||||
|
||||
describe('onChange', () => {
|
||||
it('should notify the directive when a group of records changes', () => {
|
||||
var cd = _createWithoutHydrate('groupChanges').changeDetector;
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1, directive2], []));
|
||||
cd.detectChanges();
|
||||
expect(directive1.changes).toEqual({'a': 1, 'b': 2});
|
||||
expect(directive2.changes).toEqual({'a': 3});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onCheck', () => {
|
||||
it('should notify the directive when it is checked', () => {
|
||||
var cd = _createWithoutHydrate('directiveOnCheck').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []));
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onCheckCalled).toBe(true);
|
||||
directive1.onCheckCalled = false;
|
||||
|
||||
cd.detectChanges();
|
||||
expect(directive1.onCheckCalled).toBe(true);
|
||||
});
|
||||
|
||||
it('should not call onCheck in detectNoChanges', () => {
|
||||
var cd = _createWithoutHydrate('directiveOnCheck').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []));
|
||||
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.onCheckCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onInit', () => {
|
||||
it('should notify the directive after it has been checked the first time', () => {
|
||||
var cd = _createWithoutHydrate('directiveOnInit').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []));
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onInitCalled).toBe(true);
|
||||
|
||||
directive1.onInitCalled = false;
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onInitCalled).toBe(false);
|
||||
});
|
||||
|
||||
it('should not call onInit in detectNoChanges', () => {
|
||||
var cd = _createWithoutHydrate('directiveOnInit').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []));
|
||||
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.onInitCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onAllChangesDone', () => {
|
||||
it('should be called after processing all the children', () => {
|
||||
var cd = _createWithoutHydrate('emptyWithDirectiveRecords').changeDetector;
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1, directive2], []));
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onChangesDoneCalled).toBe(true);
|
||||
expect(directive2.onChangesDoneCalled).toBe(true);
|
||||
|
||||
// reset directives
|
||||
directive1.onChangesDoneCalled = false;
|
||||
directive2.onChangesDoneCalled = false;
|
||||
|
||||
// Verify that checking should not call them.
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.onChangesDoneCalled).toBe(false);
|
||||
expect(directive2.onChangesDoneCalled).toBe(false);
|
||||
|
||||
// re-verify that changes are still detected
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onChangesDoneCalled).toBe(true);
|
||||
expect(directive2.onChangesDoneCalled).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
it('should not be called when onAllChangesDone is false', () => {
|
||||
var cd = _createWithoutHydrate('noCallbacks').changeDetector;
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive1], []));
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onChangesDoneCalled).toEqual(false);
|
||||
});
|
||||
|
||||
it('should be called in reverse order so the child is always notified before the parent',
|
||||
() => {
|
||||
var cd = _createWithoutHydrate('emptyWithDirectiveRecords').changeDetector;
|
||||
|
||||
var onChangesDoneCalls = [];
|
||||
var td1;
|
||||
td1 = new TestDirective(() => ListWrapper.push(onChangesDoneCalls, td1));
|
||||
var td2;
|
||||
td2 = new TestDirective(() => ListWrapper.push(onChangesDoneCalls, td2));
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([td1, td2], []));
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(onChangesDoneCalls).toEqual([td2, td1]);
|
||||
});
|
||||
|
||||
it('should be called before processing shadow dom children', () => {
|
||||
var parent = _createWithoutHydrate('directNoDispatcher').changeDetector;
|
||||
var child = _createWithoutHydrate('directNoDispatcher').changeDetector;
|
||||
parent.addShadowDomChild(child);
|
||||
|
||||
var orderOfOperations = [];
|
||||
|
||||
var directiveInShadowDom = null;
|
||||
directiveInShadowDom =
|
||||
new TestDirective(() => { ListWrapper.push(orderOfOperations, directiveInShadowDom); });
|
||||
var parentDirective = null;
|
||||
parentDirective =
|
||||
new TestDirective(() => { ListWrapper.push(orderOfOperations, parentDirective); });
|
||||
|
||||
parent.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([parentDirective], []));
|
||||
child.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directiveInShadowDom], []));
|
||||
|
||||
parent.detectChanges();
|
||||
expect(orderOfOperations).toEqual([parentDirective, directiveInShadowDom]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// TODO(kegluneq): Insert describe('reading directives', ...) testcases.
|
||||
describe('reading directives', () => {
|
||||
it('should read directive properties', () => {
|
||||
var directive = new TestDirective();
|
||||
directive.a = 'aaa';
|
||||
|
||||
var val = _createWithoutHydrate('readingDirectives');
|
||||
val.changeDetector.hydrate(_DEFAULT_CONTEXT, null, new FakeDirectives([directive], []));
|
||||
|
||||
val.changeDetector.detectChanges();
|
||||
|
||||
expect(val.dispatcher.loggedValues).toEqual(['aaa']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('enforce no new changes', () => {
|
||||
it('should throw when a record gets changed after it has been checked', () => {
|
||||
|
@ -402,14 +584,9 @@ export function main() {
|
|||
});
|
||||
|
||||
describe('mode', () => {
|
||||
var _createWithoutHydrate = function(expression: string) {
|
||||
var registry = null;
|
||||
return _getProtoChangeDetector(getDefinition(expression).cdDef, registry).instantiate(new TestDispatcher());
|
||||
};
|
||||
|
||||
it('should set the mode to CHECK_ALWAYS when the default change detection is used',
|
||||
() => {
|
||||
var cd = _createWithoutHydrate('emptyUsingDefaultStrategy');
|
||||
var cd = _createWithoutHydrate('emptyUsingDefaultStrategy').changeDetector;
|
||||
expect(cd.mode).toEqual(null);
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, null);
|
||||
|
@ -417,7 +594,7 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should set the mode to CHECK_ONCE when the push change detection is used', () => {
|
||||
var cd = _createWithoutHydrate('emptyUsingOnPushStrategy');
|
||||
var cd = _createWithoutHydrate('emptyUsingOnPushStrategy').changeDetector;
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, null);
|
||||
|
||||
expect(cd.mode).toEqual(CHECK_ONCE);
|
||||
|
@ -468,7 +645,7 @@ export function main() {
|
|||
var directives;
|
||||
|
||||
beforeEach(() => {
|
||||
checkedDetector = _createWithoutHydrate('emptyUsingOnPushStrategy');
|
||||
checkedDetector = _createWithoutHydrate('emptyUsingOnPushStrategy').changeDetector;
|
||||
checkedDetector.hydrate(_DEFAULT_CONTEXT, null, null);
|
||||
checkedDetector.mode = CHECKED;
|
||||
|
||||
|
@ -477,7 +654,7 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should set the mode to CHECK_ONCE when a binding is updated', () => {
|
||||
var cd = _createWithoutHydrate('onPushRecordsUsingDefaultStrategy');
|
||||
var cd = _createWithoutHydrate('onPushRecordsUsingDefaultStrategy').changeDetector;
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, directives);
|
||||
|
||||
expect(checkedDetector.mode).toEqual(CHECKED);
|
||||
|
@ -647,313 +824,6 @@ export function main() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("change detection", () => {
|
||||
StringMapWrapper.forEach(
|
||||
{
|
||||
"dynamic": (bindingRecords, variableBindings = null, directiveRecords = null,
|
||||
registry = null, strategy = null) =>
|
||||
new DynamicProtoChangeDetector(
|
||||
registry, new ChangeDetectorDefinition(
|
||||
null, strategy,
|
||||
isBlank(variableBindings) ? [] : variableBindings,
|
||||
isBlank(bindingRecords) ? [] : bindingRecords,
|
||||
isBlank(directiveRecords) ? [] : directiveRecords)),
|
||||
|
||||
"JIT": (bindingRecords, variableBindings = null, directiveRecords = null, registry = null,
|
||||
strategy = null) =>
|
||||
new JitProtoChangeDetector(
|
||||
registry, new ChangeDetectorDefinition(
|
||||
null,
|
||||
strategy, isBlank(variableBindings) ? [] :
|
||||
variableBindings,
|
||||
isBlank(bindingRecords) ? [] : bindingRecords,
|
||||
isBlank(directiveRecords) ? [] : directiveRecords))
|
||||
|
||||
},
|
||||
(createProtoChangeDetector, name) => {
|
||||
|
||||
if (name == "JIT" && IS_DARTIUM) return;
|
||||
|
||||
var parser = new Parser(new Lexer());
|
||||
|
||||
function ast(exp: string, location: string = 'location') {
|
||||
return parser.parseBinding(exp, location);
|
||||
}
|
||||
|
||||
function dirs(directives: List<any>) { return new FakeDirectives(directives, []); }
|
||||
|
||||
describe(`${name} change detection`, () => {
|
||||
var dispatcher;
|
||||
|
||||
beforeEach(() => { dispatcher = new TestDispatcher(); });
|
||||
|
||||
it("should support interpolation", () => {
|
||||
var ast = parser.parseInterpolation("B{{a}}A", "location");
|
||||
var pcd = createProtoChangeDetector([BindingRecord.createForElement(ast, 0, "memo")]);
|
||||
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
cd.hydrate(new TestData("value"), null, null);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(dispatcher.log).toEqual(["memo=BvalueA"]);
|
||||
});
|
||||
|
||||
describe("change notification", () => {
|
||||
describe("updating directives", () => {
|
||||
var dirRecord1 = new DirectiveRecord({
|
||||
directiveIndex: new DirectiveIndex(0, 0),
|
||||
callOnChange: true,
|
||||
callOnCheck: true,
|
||||
callOnAllChangesDone: true
|
||||
});
|
||||
|
||||
var dirRecord2 = new DirectiveRecord({
|
||||
directiveIndex: new DirectiveIndex(0, 1),
|
||||
callOnChange: true,
|
||||
callOnCheck: true,
|
||||
callOnAllChangesDone: true
|
||||
});
|
||||
|
||||
var dirRecordNoCallbacks = new DirectiveRecord({
|
||||
directiveIndex: new DirectiveIndex(0, 0),
|
||||
callOnChange: false,
|
||||
callOnCheck: false,
|
||||
callOnAllChangesDone: false
|
||||
});
|
||||
|
||||
function updateA(exp: string, dirRecord) {
|
||||
return BindingRecord.createForDirective(ast(exp), "a", (o, v) => o.a = v,
|
||||
dirRecord);
|
||||
}
|
||||
|
||||
function updateB(exp: string, dirRecord) {
|
||||
return BindingRecord.createForDirective(ast(exp), "b", (o, v) => o.b = v,
|
||||
dirRecord);
|
||||
}
|
||||
|
||||
var directive1;
|
||||
var directive2;
|
||||
|
||||
beforeEach(() => {
|
||||
directive1 = new TestDirective();
|
||||
directive2 = new TestDirective();
|
||||
});
|
||||
|
||||
it("should happen directly, without invoking the dispatcher", () => {
|
||||
var pcd =
|
||||
createProtoChangeDetector([updateA("42", dirRecord1)], [], [dirRecord1]);
|
||||
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, dirs([directive1]));
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(dispatcher.loggedValues).toEqual([]);
|
||||
expect(directive1.a).toEqual(42);
|
||||
});
|
||||
|
||||
describe("onChange", () => {
|
||||
it("should notify the directive when a group of records changes", () => {
|
||||
var pcd = createProtoChangeDetector([
|
||||
updateA("1", dirRecord1),
|
||||
updateB("2", dirRecord1),
|
||||
BindingRecord.createDirectiveOnChange(dirRecord1),
|
||||
updateA("3", dirRecord2),
|
||||
BindingRecord.createDirectiveOnChange(dirRecord2)
|
||||
],
|
||||
[], [dirRecord1, dirRecord2]);
|
||||
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, dirs([directive1, directive2]));
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.changes).toEqual({'a': 1, 'b': 2});
|
||||
expect(directive2.changes).toEqual({'a': 3});
|
||||
});
|
||||
});
|
||||
|
||||
describe("onCheck", () => {
|
||||
it("should notify the directive when it is checked", () => {
|
||||
var pcd = createProtoChangeDetector(
|
||||
[BindingRecord.createDirectiveOnCheck(dirRecord1)], [], [dirRecord1]);
|
||||
|
||||
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, dirs([directive1]));
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onCheckCalled).toBe(true);
|
||||
|
||||
directive1.onCheckCalled = false;
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onCheckCalled).toBe(true);
|
||||
});
|
||||
|
||||
it("should not call onCheck in detectNoChanges", () => {
|
||||
var pcd = createProtoChangeDetector(
|
||||
[BindingRecord.createDirectiveOnCheck(dirRecord1)], [], [dirRecord1]);
|
||||
|
||||
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, dirs([directive1]));
|
||||
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.onCheckCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("onInit", () => {
|
||||
it("should notify the directive after it has been checked the first time", () => {
|
||||
var pcd = createProtoChangeDetector(
|
||||
[BindingRecord.createDirectiveOnInit(dirRecord1)], [], [dirRecord1]);
|
||||
|
||||
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, dirs([directive1]));
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onInitCalled).toBe(true);
|
||||
|
||||
directive1.onInitCalled = false;
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onInitCalled).toBe(false);
|
||||
});
|
||||
|
||||
it("should not call onInit in detectNoChanges", () => {
|
||||
var pcd = createProtoChangeDetector(
|
||||
[BindingRecord.createDirectiveOnInit(dirRecord1)], [], [dirRecord1]);
|
||||
|
||||
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, dirs([directive1]));
|
||||
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.onInitCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("onAllChangesDone", () => {
|
||||
it("should be called after processing all the children", () => {
|
||||
var pcd = createProtoChangeDetector([], [], [dirRecord1, dirRecord2]);
|
||||
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, dirs([directive1, directive2]));
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onChangesDoneCalled).toBe(true);
|
||||
expect(directive2.onChangesDoneCalled).toBe(true);
|
||||
|
||||
// reset directives
|
||||
directive1.onChangesDoneCalled = false;
|
||||
directive2.onChangesDoneCalled = false;
|
||||
|
||||
// Verify that checking should not call them.
|
||||
cd.checkNoChanges();
|
||||
|
||||
expect(directive1.onChangesDoneCalled).toBe(false);
|
||||
expect(directive2.onChangesDoneCalled).toBe(false);
|
||||
|
||||
// re-verify that changes are still detected
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onChangesDoneCalled).toBe(true);
|
||||
expect(directive2.onChangesDoneCalled).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
it("should not be called when onAllChangesDone is false", () => {
|
||||
var pcd = createProtoChangeDetector([updateA("1", dirRecordNoCallbacks)], [],
|
||||
[dirRecordNoCallbacks]);
|
||||
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, dirs([directive1]));
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(directive1.onChangesDoneCalled).toEqual(false);
|
||||
});
|
||||
|
||||
it("should be called in reverse order so the child is always notified before the parent",
|
||||
() => {
|
||||
var pcd = createProtoChangeDetector([], [], [dirRecord1, dirRecord2]);
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
|
||||
var onChangesDoneCalls = [];
|
||||
var td1;
|
||||
td1 = new TestDirective(() => ListWrapper.push(onChangesDoneCalls, td1));
|
||||
var td2;
|
||||
td2 = new TestDirective(() => ListWrapper.push(onChangesDoneCalls, td2));
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, dirs([td1, td2]));
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(onChangesDoneCalls).toEqual([td2, td1]);
|
||||
});
|
||||
|
||||
it("should be called before processing shadow dom children", () => {
|
||||
var pcd = createProtoChangeDetector([], null, [dirRecord1]);
|
||||
var shadowDomChildPCD =
|
||||
createProtoChangeDetector([updateA("1", dirRecord1)], null, [dirRecord1]);
|
||||
|
||||
var parent = pcd.instantiate(dispatcher);
|
||||
|
||||
var child = shadowDomChildPCD.instantiate(dispatcher);
|
||||
parent.addShadowDomChild(child);
|
||||
|
||||
var directiveInShadowDom = new TestDirective();
|
||||
var parentDirective =
|
||||
new TestDirective(() => { expect(directiveInShadowDom.a).toBe(null); });
|
||||
|
||||
parent.hydrate(_DEFAULT_CONTEXT, null, dirs([parentDirective]));
|
||||
child.hydrate(_DEFAULT_CONTEXT, null, dirs([directiveInShadowDom]));
|
||||
|
||||
parent.detectChanges();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("reading directives", () => {
|
||||
var index = new DirectiveIndex(0, 0);
|
||||
var dirRecord = new DirectiveRecord({directiveIndex: new DirectiveIndex(0, 0)});
|
||||
|
||||
it("should read directive properties", () => {
|
||||
var directive = new TestDirective();
|
||||
directive.a = "aaa";
|
||||
|
||||
var pcd = createProtoChangeDetector(
|
||||
[BindingRecord.createForHostProperty(index, ast("a"), "prop")], null,
|
||||
[dirRecord]);
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
cd.hydrate(_DEFAULT_CONTEXT, null, dirs([directive]));
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(dispatcher.loggedValues).toEqual(['aaa']);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class CountingPipe extends Pipe {
|
||||
|
|
|
@ -16,9 +16,13 @@ import {ReflectionCapabilities} from 'angular2/src/reflection/reflection_capabil
|
|||
|
||||
var _parser = new Parser(new Lexer());
|
||||
|
||||
function _createBindingRecords(expression: string): List<BindingRecord> {
|
||||
function _getParser() {
|
||||
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||
var ast = _parser.parseBinding(expression, 'location');
|
||||
return _parser;
|
||||
}
|
||||
|
||||
function _createBindingRecords(expression: string): List<BindingRecord> {
|
||||
var ast = _getParser().parseBinding(expression, 'location');
|
||||
return [BindingRecord.createForElement(ast, 0, PROP_NAME)];
|
||||
}
|
||||
|
||||
|
@ -49,6 +53,11 @@ export function getDefinition(id: string): TestDefinition {
|
|||
let cdDef = val.createChangeDetectorDefinition();
|
||||
cdDef.id = id;
|
||||
testDef = new TestDefinition(id, cdDef, null);
|
||||
} else if (StringMapWrapper.contains(_DirectiveUpdating.availableDefinitions, id)) {
|
||||
let val = StringMapWrapper.get(_DirectiveUpdating.availableDefinitions, id);
|
||||
let cdDef = val.createChangeDetectorDefinition();
|
||||
cdDef.id = id;
|
||||
testDef = new TestDefinition(id, cdDef, null);
|
||||
} else if (ListWrapper.indexOf(_availableDefinitions, id) >= 0) {
|
||||
var strategy = null;
|
||||
var variableBindings = [];
|
||||
|
@ -74,7 +83,11 @@ export class TestDefinition {
|
|||
* `ChangeDetector` classes.
|
||||
*/
|
||||
export function getAllDefinitions(): List<TestDefinition> {
|
||||
return ListWrapper.map(_availableDefinitions, (id) => getDefinition(id));
|
||||
var allDefs = _availableDefinitions;
|
||||
allDefs = ListWrapper.concat(allDefs, StringMapWrapper.keys(_ExpressionWithLocals.availableDefinitions));
|
||||
allDefs = ListWrapper.concat(allDefs, StringMapWrapper.keys(_ExpressionWithMode.availableDefinitions));
|
||||
allDefs = ListWrapper.concat(allDefs, StringMapWrapper.keys(_DirectiveUpdating.availableDefinitions));
|
||||
return ListWrapper.map(allDefs, (id) => getDefinition(id));
|
||||
}
|
||||
|
||||
class _ExpressionWithLocals {
|
||||
|
@ -121,7 +134,7 @@ class _ExpressionWithMode {
|
|||
var dirRecordWithOnPush =
|
||||
new DirectiveRecord({directiveIndex: new DirectiveIndex(0, 0), changeDetection: ON_PUSH});
|
||||
var updateDirWithOnPushRecord =
|
||||
BindingRecord.createForDirective(_parser.parseBinding('42', 'location'), 'a',
|
||||
BindingRecord.createForDirective(_getParser().parseBinding('42', 'location'), 'a',
|
||||
(o, v) => (<any>o).a = v, dirRecordWithOnPush);
|
||||
bindingRecords = [updateDirWithOnPushRecord];
|
||||
directiveRecords = [dirRecordWithOnPush];
|
||||
|
@ -144,61 +157,143 @@ class _ExpressionWithMode {
|
|||
};
|
||||
}
|
||||
|
||||
class _DirectiveUpdating {
|
||||
constructor(private _bindingRecords: List<BindingRecord>,
|
||||
private _directiveRecords: List<DirectiveRecord>) {}
|
||||
|
||||
createChangeDetectorDefinition(): ChangeDetectorDefinition {
|
||||
var strategy = null;
|
||||
var variableBindings = [];
|
||||
|
||||
return new ChangeDetectorDefinition('(empty id)', strategy, variableBindings,
|
||||
this._bindingRecords, this._directiveRecords);
|
||||
}
|
||||
|
||||
static updateA(expression: string, dirRecord): BindingRecord {
|
||||
return BindingRecord.createForDirective(_getParser().parseBinding(expression, 'location'), 'a',
|
||||
(o, v) => (<any>o).a = v, dirRecord);
|
||||
}
|
||||
|
||||
static updateB(expression: string, dirRecord): BindingRecord {
|
||||
return BindingRecord.createForDirective(_getParser().parseBinding(expression, 'location'), 'b',
|
||||
(o, v) => (<any>o).b = v, dirRecord);
|
||||
}
|
||||
|
||||
static basicRecords: List<DirectiveRecord> = [
|
||||
new DirectiveRecord({
|
||||
directiveIndex: new DirectiveIndex(0, 0),
|
||||
callOnChange: true,
|
||||
callOnCheck: true,
|
||||
callOnAllChangesDone: true
|
||||
}),
|
||||
new DirectiveRecord({
|
||||
directiveIndex: new DirectiveIndex(0, 1),
|
||||
callOnChange: true,
|
||||
callOnCheck: true,
|
||||
callOnAllChangesDone: true
|
||||
})
|
||||
];
|
||||
|
||||
static recordNoCallbacks = new DirectiveRecord({
|
||||
directiveIndex: new DirectiveIndex(0, 0),
|
||||
callOnChange: false,
|
||||
callOnCheck: false,
|
||||
callOnAllChangesDone: false
|
||||
});
|
||||
|
||||
/**
|
||||
* Map from test id to _DirectiveUpdating.
|
||||
* Definitions in this map define definitions which allow testing directive updating.
|
||||
*/
|
||||
static availableDefinitions: StringMap<string, _DirectiveUpdating> = {
|
||||
'directNoDispatcher': new _DirectiveUpdating(
|
||||
[_DirectiveUpdating.updateA('42', _DirectiveUpdating.basicRecords[0])],
|
||||
[_DirectiveUpdating.basicRecords[0]]),
|
||||
'groupChanges': new _DirectiveUpdating(
|
||||
[
|
||||
_DirectiveUpdating.updateA('1', _DirectiveUpdating.basicRecords[0]),
|
||||
_DirectiveUpdating.updateB('2', _DirectiveUpdating.basicRecords[0]),
|
||||
BindingRecord.createDirectiveOnChange(_DirectiveUpdating.basicRecords[0]),
|
||||
_DirectiveUpdating.updateA('3', _DirectiveUpdating.basicRecords[1]),
|
||||
BindingRecord.createDirectiveOnChange(_DirectiveUpdating.basicRecords[1])
|
||||
],
|
||||
[_DirectiveUpdating.basicRecords[0], _DirectiveUpdating.basicRecords[1]]),
|
||||
'directiveOnCheck': new _DirectiveUpdating(
|
||||
[BindingRecord.createDirectiveOnCheck(_DirectiveUpdating.basicRecords[0])],
|
||||
[_DirectiveUpdating.basicRecords[0]]),
|
||||
'directiveOnInit': new _DirectiveUpdating(
|
||||
[BindingRecord.createDirectiveOnInit(_DirectiveUpdating.basicRecords[0])],
|
||||
[_DirectiveUpdating.basicRecords[0]]),
|
||||
'emptyWithDirectiveRecords': new _DirectiveUpdating(
|
||||
[], [_DirectiveUpdating.basicRecords[0], _DirectiveUpdating.basicRecords[1]]),
|
||||
'noCallbacks': new _DirectiveUpdating(
|
||||
[_DirectiveUpdating.updateA('1', _DirectiveUpdating.recordNoCallbacks)],
|
||||
[_DirectiveUpdating.recordNoCallbacks]),
|
||||
'readingDirectives': new _DirectiveUpdating([
|
||||
BindingRecord.createForHostProperty(new DirectiveIndex(0, 0),
|
||||
_getParser().parseBinding('a', 'location'), PROP_NAME)
|
||||
],
|
||||
[_DirectiveUpdating.basicRecords[0]]),
|
||||
'interpolation': new _DirectiveUpdating([
|
||||
BindingRecord.createForElement(_getParser().parseInterpolation('B{{a}}A', 'location'), 0,
|
||||
PROP_NAME)
|
||||
],
|
||||
[])
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of all test definitions this config supplies.
|
||||
* Items in this list that do not appear in other structures define tests with expressions
|
||||
* equivalent to their ids.
|
||||
*/
|
||||
var _availableDefinitions = ListWrapper.concat(
|
||||
[
|
||||
'10',
|
||||
'"str"',
|
||||
'"a\n\nb"',
|
||||
'10 + 2',
|
||||
'10 - 2',
|
||||
'10 * 2',
|
||||
'10 / 2',
|
||||
'11 % 2',
|
||||
'1 == 1',
|
||||
'1 != 1',
|
||||
'1 == true',
|
||||
'1 === 1',
|
||||
'1 !== 1',
|
||||
'1 === true',
|
||||
'1 < 2',
|
||||
'2 < 1',
|
||||
'1 > 2',
|
||||
'2 > 1',
|
||||
'1 <= 2',
|
||||
'2 <= 2',
|
||||
'2 <= 1',
|
||||
'2 >= 1',
|
||||
'2 >= 2',
|
||||
'1 >= 2',
|
||||
'true && true',
|
||||
'true && false',
|
||||
'true || false',
|
||||
'false || false',
|
||||
'!true',
|
||||
'!!true',
|
||||
'1 < 2 ? 1 : 2',
|
||||
'1 > 2 ? 1 : 2',
|
||||
'["foo", "bar"][0]',
|
||||
'{"foo": "bar"}["foo"]',
|
||||
'name',
|
||||
'[1, 2]',
|
||||
'[1, a]',
|
||||
'{z: 1}',
|
||||
'{z: a}',
|
||||
'name | pipe',
|
||||
'value',
|
||||
'a',
|
||||
'address.city',
|
||||
'address?.city',
|
||||
'address?.toString()',
|
||||
'sayHi("Jim")',
|
||||
'a()(99)',
|
||||
'a.sayHi("Jim")'
|
||||
],
|
||||
ListWrapper.concat(StringMapWrapper.keys(_ExpressionWithLocals.availableDefinitions),
|
||||
StringMapWrapper.keys(_ExpressionWithMode.availableDefinitions)));
|
||||
var _availableDefinitions = [
|
||||
'10',
|
||||
'"str"',
|
||||
'"a\n\nb"',
|
||||
'10 + 2',
|
||||
'10 - 2',
|
||||
'10 * 2',
|
||||
'10 / 2',
|
||||
'11 % 2',
|
||||
'1 == 1',
|
||||
'1 != 1',
|
||||
'1 == true',
|
||||
'1 === 1',
|
||||
'1 !== 1',
|
||||
'1 === true',
|
||||
'1 < 2',
|
||||
'2 < 1',
|
||||
'1 > 2',
|
||||
'2 > 1',
|
||||
'1 <= 2',
|
||||
'2 <= 2',
|
||||
'2 <= 1',
|
||||
'2 >= 1',
|
||||
'2 >= 2',
|
||||
'1 >= 2',
|
||||
'true && true',
|
||||
'true && false',
|
||||
'true || false',
|
||||
'false || false',
|
||||
'!true',
|
||||
'!!true',
|
||||
'1 < 2 ? 1 : 2',
|
||||
'1 > 2 ? 1 : 2',
|
||||
'["foo", "bar"][0]',
|
||||
'{"foo": "bar"}["foo"]',
|
||||
'name',
|
||||
'[1, 2]',
|
||||
'[1, a]',
|
||||
'{z: 1}',
|
||||
'{z: a}',
|
||||
'name | pipe',
|
||||
'value',
|
||||
'a',
|
||||
'address.city',
|
||||
'address?.city',
|
||||
'address?.toString()',
|
||||
'sayHi("Jim")',
|
||||
'a()(99)',
|
||||
'a.sayHi("Jim")'
|
||||
];
|
||||
|
|
Loading…
Reference in New Issue