feat(change_detection): add support for pipes
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
import {describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
import {ArrayChanges} from 'angular2/src/change_detection/array_changes';
|
||||
import {ArrayChanges} from 'angular2/src/change_detection/pipes/array_changes';
|
||||
|
||||
import {NumberWrapper} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
|
||||
@ -23,10 +23,10 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should support list and iterables', () => {
|
||||
expect(ArrayChanges.supports([])).toBeTruthy();
|
||||
expect(ArrayChanges.supports(new TestIterable())).toBeTruthy();
|
||||
expect(ArrayChanges.supports(MapWrapper.create())).toBeFalsy();
|
||||
expect(ArrayChanges.supports(null)).toBeFalsy();
|
||||
expect(ArrayChanges.supportsObj([])).toBeTruthy();
|
||||
expect(ArrayChanges.supportsObj(new TestIterable())).toBeTruthy();
|
||||
expect(ArrayChanges.supportsObj(MapWrapper.create())).toBeFalsy();
|
||||
expect(ArrayChanges.supportsObj(null)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should support iterables', () => {
|
||||
|
@ -8,6 +8,7 @@ import {Lexer} from 'angular2/src/change_detection/parser/lexer';
|
||||
import {arrayChangesAsString, kvChangesAsString} from './util';
|
||||
|
||||
import {ChangeDispatcher, DynamicChangeDetector, ChangeDetectionError, ContextWithVariableBindings,
|
||||
PipeRegistry, NO_CHANGE,
|
||||
CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from 'angular2/change_detection';
|
||||
|
||||
|
||||
@ -17,8 +18,8 @@ import {JitProtoChangeDetector, DynamicProtoChangeDetector} from 'angular2/src/c
|
||||
export function main() {
|
||||
describe("change detection", () => {
|
||||
StringMapWrapper.forEach(
|
||||
{ "dynamic": () => new DynamicProtoChangeDetector(),
|
||||
"JIT": () => new JitProtoChangeDetector()
|
||||
{ "dynamic": (registry = null) => new DynamicProtoChangeDetector(registry),
|
||||
"JIT": (registry = null) => new JitProtoChangeDetector(registry)
|
||||
}, (createProtoChangeDetector, name) => {
|
||||
|
||||
if (name == "JIT" && IS_DARTIUM) return;
|
||||
@ -29,8 +30,8 @@ export function main() {
|
||||
}
|
||||
|
||||
function createChangeDetector(memo:string, exp:string, context = null, formatters = null,
|
||||
structural = false) {
|
||||
var pcd = createProtoChangeDetector();
|
||||
registry = null, structural = false) {
|
||||
var pcd = createProtoChangeDetector(registry);
|
||||
pcd.addAst(ast(exp), memo, memo, structural);
|
||||
|
||||
var dispatcher = new TestDispatcher();
|
||||
@ -41,8 +42,8 @@ export function main() {
|
||||
}
|
||||
|
||||
function executeWatch(memo:string, exp:string, context = null, formatters = null,
|
||||
content = false) {
|
||||
var res = createChangeDetector(memo, exp, context, formatters, content);
|
||||
registry = null, content = false) {
|
||||
var res = createChangeDetector(memo, exp, context, formatters, registry, content);
|
||||
res["changeDetector"].detectChanges();
|
||||
return res["dispatcher"].log;
|
||||
}
|
||||
@ -281,124 +282,6 @@ export function main() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("collections", () => {
|
||||
it("should not register a change when going from null to null", () => {
|
||||
var context = new TestData(null);
|
||||
|
||||
var c = createChangeDetector('a', 'a', context, null, true);
|
||||
var cd = c["changeDetector"];
|
||||
var dispatcher = c["dispatcher"];
|
||||
|
||||
cd.detectChanges();
|
||||
expect(dispatcher.log).toEqual([]);
|
||||
});
|
||||
|
||||
it("should register changes when switching from null to collection and back", () => {
|
||||
var context = new TestData(null);
|
||||
|
||||
var c = createChangeDetector('a', 'a', context, null, true);
|
||||
var cd = c["changeDetector"];
|
||||
var dispatcher = c["dispatcher"];
|
||||
|
||||
context.a = [0];
|
||||
cd.detectChanges();
|
||||
|
||||
expect(dispatcher.log).toEqual(["a=" +
|
||||
arrayChangesAsString({
|
||||
collection: ['0[null->0]'],
|
||||
additions: ['0[null->0]']
|
||||
})
|
||||
]);
|
||||
dispatcher.clear();
|
||||
|
||||
context.a = null;
|
||||
cd.detectChanges();
|
||||
expect(dispatcher.log).toEqual(['a=null']);
|
||||
});
|
||||
|
||||
describe("list", () => {
|
||||
it("should support list changes", () => {
|
||||
var context = new TestData([1, 2]);
|
||||
|
||||
expect(executeWatch("a", "a", context, null, true))
|
||||
.toEqual(["a=" +
|
||||
arrayChangesAsString({
|
||||
collection: ['1[null->0]', '2[null->1]'],
|
||||
additions: ['1[null->0]', '2[null->1]']
|
||||
})]);
|
||||
});
|
||||
|
||||
it("should handle reference changes", () => {
|
||||
var context = new TestData([1, 2]);
|
||||
var objs = createChangeDetector("a", "a", context, null, true);
|
||||
var cd = objs["changeDetector"];
|
||||
var dispatcher = objs["dispatcher"];
|
||||
cd.detectChanges();
|
||||
dispatcher.clear();
|
||||
|
||||
context.a = [2, 1];
|
||||
cd.detectChanges();
|
||||
expect(dispatcher.log).toEqual(["a=" +
|
||||
arrayChangesAsString({
|
||||
collection: ['2[1->0]', '1[0->1]'],
|
||||
previous: ['1[0->1]', '2[1->0]'],
|
||||
moves: ['2[1->0]', '1[0->1]']
|
||||
})]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("map", () => {
|
||||
it("should support map changes", () => {
|
||||
var map = MapWrapper.create();
|
||||
MapWrapper.set(map, "foo", "bar");
|
||||
var context = new TestData(map);
|
||||
expect(executeWatch("a", "a", context, null, true))
|
||||
.toEqual(["a=" +
|
||||
kvChangesAsString({
|
||||
map: ['foo[null->bar]'],
|
||||
additions: ['foo[null->bar]']
|
||||
})]);
|
||||
});
|
||||
|
||||
it("should handle reference changes", () => {
|
||||
var map = MapWrapper.create();
|
||||
MapWrapper.set(map, "foo", "bar");
|
||||
var context = new TestData(map);
|
||||
var objs = createChangeDetector("a", "a", context, null, true);
|
||||
var cd = objs["changeDetector"];
|
||||
var dispatcher = objs["dispatcher"];
|
||||
cd.detectChanges();
|
||||
dispatcher.clear();
|
||||
|
||||
context.a = MapWrapper.create();
|
||||
MapWrapper.set(context.a, "bar", "foo");
|
||||
cd.detectChanges();
|
||||
expect(dispatcher.log).toEqual(["a=" +
|
||||
kvChangesAsString({
|
||||
map: ['bar[null->foo]'],
|
||||
previous: ['foo[bar->null]'],
|
||||
additions: ['bar[null->foo]'],
|
||||
removals: ['foo[bar->null]']
|
||||
})]);
|
||||
});
|
||||
});
|
||||
|
||||
if (!IS_DARTIUM) {
|
||||
describe("js objects", () => {
|
||||
it("should support object changes", () => {
|
||||
var map = {"foo": "bar"};
|
||||
var context = new TestData(map);
|
||||
expect(executeWatch("a", "a", context, null, true))
|
||||
.toEqual(["a=" +
|
||||
kvChangesAsString({
|
||||
map: ['foo[null->bar]'],
|
||||
additions: ['foo[null->bar]']
|
||||
})]);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("ContextWithVariableBindings", () => {
|
||||
it('should read a field from ContextWithVariableBindings', () => {
|
||||
var locals = new ContextWithVariableBindings(null,
|
||||
@ -543,10 +426,132 @@ export function main() {
|
||||
expect(checkedChild.mode).toEqual(CHECK_ONCE);
|
||||
});
|
||||
});
|
||||
|
||||
describe("pipes", () => {
|
||||
it("should support pipes", () => {
|
||||
var registry = new FakePipeRegistry(() => new CountingPipe());
|
||||
var ctx = new Person("Megatron");
|
||||
|
||||
var c = createChangeDetector("memo", "name", ctx, null, registry, true);
|
||||
var cd = c["changeDetector"];
|
||||
var dispatcher = c["dispatcher"];
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(dispatcher.log).toEqual(['memo=Megatron state:0']);
|
||||
|
||||
dispatcher.clear();
|
||||
cd.detectChanges();
|
||||
|
||||
expect(dispatcher.log).toEqual(['memo=Megatron state:1']);
|
||||
});
|
||||
|
||||
it("should lookup pipes in the registry when the context is not supported", () => {
|
||||
var registry = new FakePipeRegistry(() => new OncePipe());
|
||||
var ctx = new Person("Megatron");
|
||||
|
||||
var c = createChangeDetector("memo", "name", ctx, null, registry, true);
|
||||
var cd = c["changeDetector"];
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(registry.numberOfLookups).toEqual(1);
|
||||
|
||||
ctx.name = "Optimus Prime";
|
||||
cd.detectChanges();
|
||||
|
||||
expect(registry.numberOfLookups).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
it("should do nothing when returns NO_CHANGE", () => {
|
||||
var registry = new FakePipeRegistry(() => new IdentityPipe())
|
||||
var ctx = new Person("Megatron");
|
||||
|
||||
var c = createChangeDetector("memo", "name", ctx, null, registry, true);
|
||||
var cd = c["changeDetector"];
|
||||
var dispatcher = c["dispatcher"];
|
||||
|
||||
cd.detectChanges();
|
||||
cd.detectChanges();
|
||||
|
||||
expect(dispatcher.log).toEqual(['memo=Megatron']);
|
||||
|
||||
ctx.name = "Optimus Prime";
|
||||
dispatcher.clear();
|
||||
cd.detectChanges();
|
||||
|
||||
expect(dispatcher.log).toEqual(['memo=Optimus Prime']);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class CountingPipe {
|
||||
state:number;
|
||||
|
||||
constructor() {
|
||||
this.state = 0;
|
||||
}
|
||||
|
||||
supports(newValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
transform(value) {
|
||||
return `${value} state:${this.state ++}`;
|
||||
}
|
||||
}
|
||||
|
||||
class OncePipe {
|
||||
called:boolean;
|
||||
constructor() {
|
||||
this.called = false;;
|
||||
}
|
||||
|
||||
supports(newValue) {
|
||||
return !this.called;
|
||||
}
|
||||
|
||||
transform(value) {
|
||||
this.called = true;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
class IdentityPipe {
|
||||
state:any;
|
||||
|
||||
supports(newValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
transform(value) {
|
||||
if (this.state === value) {
|
||||
return NO_CHANGE;
|
||||
} else {
|
||||
this.state = value;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FakePipeRegistry extends PipeRegistry {
|
||||
numberOfLookups:number;
|
||||
factory:Function;
|
||||
|
||||
constructor(factory) {
|
||||
super({});
|
||||
this.factory = factory;
|
||||
this.numberOfLookups = 0;
|
||||
}
|
||||
|
||||
get(type:string, obj) {
|
||||
this.numberOfLookups ++;
|
||||
return this.factory();
|
||||
}
|
||||
}
|
||||
|
||||
class TestRecord {
|
||||
a;
|
||||
b;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
import {KeyValueChanges} from 'angular2/src/change_detection/keyvalue_changes';
|
||||
import {KeyValueChanges} from 'angular2/src/change_detection/pipes/keyvalue_changes';
|
||||
import {NumberWrapper, isJsObject} from 'angular2/src/facade/lang';
|
||||
import {MapWrapper} from 'angular2/src/facade/collection';
|
||||
import {kvChangesAsString} from './util';
|
||||
|
39
modules/angular2/test/change_detection/transformer_registry_spec.js
vendored
Normal file
39
modules/angular2/test/change_detection/transformer_registry_spec.js
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach} from 'angular2/test_lib';
|
||||
|
||||
import {PipeRegistry} from 'angular2/src/change_detection/pipes/pipe_registry';
|
||||
import {Pipe} from 'angular2/src/change_detection/pipes/pipe';
|
||||
|
||||
export function main() {
|
||||
describe("pipe registry", () => {
|
||||
var firstPipe = new Pipe();
|
||||
var secondPipe = new Pipe();
|
||||
|
||||
it("should return the first pipe supporting the data type", () => {
|
||||
var r = new PipeRegistry({
|
||||
"type": [
|
||||
{"supports": (obj) => false, "pipe": () => firstPipe},
|
||||
{"supports": (obj) => true, "pipe": () => secondPipe}
|
||||
]
|
||||
});
|
||||
|
||||
expect(r.get("type", "some object")).toBe(secondPipe);
|
||||
});
|
||||
|
||||
it("should throw when no matching type", () => {
|
||||
var r = new PipeRegistry({});
|
||||
expect(() => r.get("unknown", "some object")).toThrowError(
|
||||
`Cannot find a pipe for type 'unknown' object 'some object'`
|
||||
);
|
||||
});
|
||||
|
||||
it("should throw when no matching pipe", () => {
|
||||
var r = new PipeRegistry({
|
||||
"type" : []
|
||||
});
|
||||
|
||||
expect(() => r.get("type", "some object")).toThrowError(
|
||||
`Cannot find a pipe for type 'type' object 'some object'`
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user