chore(packaging): move files to match target file structure
This commit is contained in:
236
modules/angular2/test/core/compiler/pipeline/directive_parser_spec.js
vendored
Normal file
236
modules/angular2/test/core/compiler/pipeline/directive_parser_spec.js
vendored
Normal file
@ -0,0 +1,236 @@
|
||||
import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'test_lib/test_lib';
|
||||
import {isPresent} from 'facade/src/lang';
|
||||
import {ListWrapper, MapWrapper, StringMapWrapper} from 'facade/src/collection';
|
||||
import {DirectiveParser} from 'core/src/compiler/pipeline/directive_parser';
|
||||
import {CompilePipeline} from 'core/src/compiler/pipeline/compile_pipeline';
|
||||
import {CompileStep} from 'core/src/compiler/pipeline/compile_step';
|
||||
import {CompileElement} from 'core/src/compiler/pipeline/compile_element';
|
||||
import {CompileControl} from 'core/src/compiler/pipeline/compile_control';
|
||||
import {DOM} from 'facade/src/dom';
|
||||
import {Component} from 'core/src/annotations/annotations';
|
||||
import {Decorator} from 'core/src/annotations/annotations';
|
||||
import {Template} from 'core/src/annotations/annotations';
|
||||
import {TemplateConfig} from 'core/src/annotations/template_config';
|
||||
import {DirectiveMetadataReader} from 'core/src/compiler/directive_metadata_reader';
|
||||
import {Lexer, Parser} from 'change_detection/change_detection';
|
||||
|
||||
export function main() {
|
||||
describe('DirectiveParser', () => {
|
||||
var reader, directives;
|
||||
|
||||
beforeEach( () => {
|
||||
reader = new DirectiveMetadataReader();
|
||||
directives = [
|
||||
SomeDecorator,
|
||||
SomeDecoratorIgnoringChildren,
|
||||
SomeTemplate,
|
||||
SomeTemplate2,
|
||||
SomeComponent,
|
||||
SomeComponent2
|
||||
];
|
||||
});
|
||||
|
||||
function createPipeline({propertyBindings, variableBindings}={}) {
|
||||
var parser = new Parser(new Lexer());
|
||||
var annotatedDirectives = ListWrapper.create();
|
||||
for (var i=0; i<directives.length; i++) {
|
||||
ListWrapper.push(annotatedDirectives, reader.read(directives[i]));
|
||||
}
|
||||
|
||||
return new CompilePipeline([new MockStep((parent, current, control) => {
|
||||
if (isPresent(propertyBindings)) {
|
||||
StringMapWrapper.forEach(propertyBindings, (v, k) => {
|
||||
current.addPropertyBinding(k, parser.parseBinding(v, null));
|
||||
});
|
||||
}
|
||||
if (isPresent(variableBindings)) {
|
||||
current.variableBindings = MapWrapper.createFromStringMap(variableBindings);
|
||||
}
|
||||
}), new DirectiveParser(annotatedDirectives)]);
|
||||
}
|
||||
|
||||
it('should not add directives if they are not used', () => {
|
||||
var results = createPipeline().process(el('<div></div>'));
|
||||
expect(results[0].decoratorDirectives).toBe(null);
|
||||
expect(results[0].componentDirective).toBe(null);
|
||||
expect(results[0].templateDirective).toBe(null);
|
||||
});
|
||||
|
||||
describe('component directives', () => {
|
||||
it('should detect them in attributes', () => {
|
||||
var results = createPipeline().process(el('<div some-comp></div>'));
|
||||
expect(results[0].componentDirective).toEqual(reader.read(SomeComponent));
|
||||
});
|
||||
|
||||
it('component directives must be first in collected directives', () => {
|
||||
var results = createPipeline().process(el('<div some-comp some-decor></div>'));
|
||||
var dirs = results[0].getAllDirectives();
|
||||
expect(dirs.length).toEqual(2);
|
||||
expect(dirs[0]).toEqual(reader.read(SomeComponent));
|
||||
expect(dirs[1]).toEqual(reader.read(SomeDecorator));
|
||||
});
|
||||
|
||||
it('should detect them in property bindings', () => {
|
||||
var pipeline = createPipeline({propertyBindings: {
|
||||
'some-comp': 'someExpr'
|
||||
}});
|
||||
var results = pipeline.process(el('<div></div>'));
|
||||
expect(results[0].componentDirective).toEqual(reader.read(SomeComponent));
|
||||
});
|
||||
|
||||
it('should detect them in variable bindings', () => {
|
||||
var pipeline = createPipeline({variableBindings: {
|
||||
'some-comp': 'someExpr'
|
||||
}});
|
||||
var results = pipeline.process(el('<div></div>'));
|
||||
expect(results[0].componentDirective).toEqual(reader.read(SomeComponent));
|
||||
});
|
||||
|
||||
it('should not allow multiple component directives on the same element', () => {
|
||||
expect( () => {
|
||||
createPipeline().process(
|
||||
el('<div some-comp some-comp2></div>')
|
||||
);
|
||||
}).toThrowError('Only one component directive per element is allowed!');
|
||||
});
|
||||
|
||||
it('should not allow component directives on <template> elements', () => {
|
||||
expect( () => {
|
||||
createPipeline().process(
|
||||
el('<template some-comp></template>')
|
||||
);
|
||||
}).toThrowError('Only template directives are allowed on <template> elements!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('template directives', () => {
|
||||
it('should detect them in attributes', () => {
|
||||
var results = createPipeline().process(el('<template some-templ></template>'));
|
||||
expect(results[0].templateDirective).toEqual(reader.read(SomeTemplate));
|
||||
});
|
||||
|
||||
it('should detect them in property bindings', () => {
|
||||
var pipeline = createPipeline({propertyBindings: {
|
||||
'some-templ': 'someExpr'
|
||||
}});
|
||||
var results = pipeline.process(el('<template></template>'));
|
||||
expect(results[0].templateDirective).toEqual(reader.read(SomeTemplate));
|
||||
});
|
||||
|
||||
it('should detect them in variable bindings', () => {
|
||||
var pipeline = createPipeline({variableBindings: {
|
||||
'some-templ': 'someExpr'
|
||||
}});
|
||||
var results = pipeline.process(el('<template></template>'));
|
||||
expect(results[0].templateDirective).toEqual(reader.read(SomeTemplate));
|
||||
});
|
||||
|
||||
it('should not allow multiple template directives on the same element', () => {
|
||||
expect( () => {
|
||||
createPipeline().process(
|
||||
el('<template some-templ some-templ2></template>')
|
||||
);
|
||||
}).toThrowError('Only one template directive per element is allowed!');
|
||||
});
|
||||
|
||||
it('should not allow template directives on non <template> elements', () => {
|
||||
expect( () => {
|
||||
createPipeline().process(
|
||||
el('<div some-templ></div>')
|
||||
);
|
||||
}).toThrowError('Template directives need to be placed on <template> elements or elements with template attribute!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('decorator directives', () => {
|
||||
it('should detect them in attributes', () => {
|
||||
var results = createPipeline().process(el('<div some-decor></div>'));
|
||||
expect(results[0].decoratorDirectives).toEqual([reader.read(SomeDecorator)]);
|
||||
});
|
||||
|
||||
it('should detect them in property bindings', () => {
|
||||
var pipeline = createPipeline({propertyBindings: {
|
||||
'some-decor': 'someExpr'
|
||||
}});
|
||||
var results = pipeline.process(el('<div></div>'));
|
||||
expect(results[0].decoratorDirectives).toEqual([reader.read(SomeDecorator)]);
|
||||
});
|
||||
|
||||
it('should compile children by default', () => {
|
||||
var results = createPipeline().process(el('<div some-decor></div>'));
|
||||
expect(results[0].compileChildren).toEqual(true);
|
||||
});
|
||||
|
||||
it('should stop compiling children when specified in the decorator config', () => {
|
||||
var results = createPipeline().process(el('<div some-decor-ignoring-children></div>'));
|
||||
expect(results[0].compileChildren).toEqual(false);
|
||||
});
|
||||
|
||||
it('should detect them in variable bindings', () => {
|
||||
var pipeline = createPipeline({variableBindings: {
|
||||
'some-decor': 'someExpr'
|
||||
}});
|
||||
var results = pipeline.process(el('<div></div>'));
|
||||
expect(results[0].decoratorDirectives).toEqual([reader.read(SomeDecorator)]);
|
||||
});
|
||||
|
||||
it('should not allow decorator directives on <template> elements', () => {
|
||||
expect( () => {
|
||||
createPipeline().process(
|
||||
el('<template some-decor></template>')
|
||||
);
|
||||
}).toThrowError('Only template directives are allowed on <template> elements!');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
class MockStep extends CompileStep {
|
||||
processClosure:Function;
|
||||
constructor(process) {
|
||||
this.processClosure = process;
|
||||
}
|
||||
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
|
||||
this.processClosure(parent, current, control);
|
||||
}
|
||||
}
|
||||
|
||||
@Decorator({
|
||||
selector: '[some-decor]'
|
||||
})
|
||||
class SomeDecorator {}
|
||||
|
||||
@Decorator({
|
||||
selector: '[some-decor-ignoring-children]',
|
||||
compileChildren: false
|
||||
})
|
||||
class SomeDecoratorIgnoringChildren {
|
||||
}
|
||||
|
||||
@Template({
|
||||
selector: '[some-templ]'
|
||||
})
|
||||
class SomeTemplate {}
|
||||
|
||||
@Template({
|
||||
selector: '[some-templ2]'
|
||||
})
|
||||
class SomeTemplate2 {}
|
||||
|
||||
@Component({
|
||||
selector: '[some-comp]'
|
||||
})
|
||||
class SomeComponent {}
|
||||
|
||||
@Component({
|
||||
selector: '[some-comp2]'
|
||||
})
|
||||
class SomeComponent2 {}
|
||||
|
||||
@Component({
|
||||
template: new TemplateConfig({
|
||||
directives: [SomeDecorator, SomeTemplate, SomeTemplate2, SomeComponent, SomeComponent2]
|
||||
})
|
||||
})
|
||||
class MyComp {}
|
366
modules/angular2/test/core/compiler/pipeline/element_binder_builder_spec.js
vendored
Normal file
366
modules/angular2/test/core/compiler/pipeline/element_binder_builder_spec.js
vendored
Normal file
@ -0,0 +1,366 @@
|
||||
import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'test_lib/test_lib';
|
||||
import {isPresent} from 'facade/src/lang';
|
||||
import {DOM} from 'facade/src/dom';
|
||||
import {ListWrapper, MapWrapper} from 'facade/src/collection';
|
||||
|
||||
import {ElementBinderBuilder} from 'core/src/compiler/pipeline/element_binder_builder';
|
||||
import {CompilePipeline} from 'core/src/compiler/pipeline/compile_pipeline';
|
||||
import {CompileElement} from 'core/src/compiler/pipeline/compile_element';
|
||||
import {CompileStep} from 'core/src/compiler/pipeline/compile_step'
|
||||
import {CompileControl} from 'core/src/compiler/pipeline/compile_control';
|
||||
|
||||
import {Decorator} from 'core/src/annotations/annotations';
|
||||
import {Template} from 'core/src/annotations/annotations';
|
||||
import {Component} from 'core/src/annotations/annotations';
|
||||
import {ProtoView, ElementPropertyMemento, DirectivePropertyMemento} from 'core/src/compiler/view';
|
||||
import {ProtoElementInjector} from 'core/src/compiler/element_injector';
|
||||
import {DirectiveMetadataReader} from 'core/src/compiler/directive_metadata_reader';
|
||||
|
||||
import {ChangeDetector, Lexer, Parser, DynamicProtoChangeDetector,
|
||||
} from 'change_detection/change_detection';
|
||||
import {Injector} from 'di/di';
|
||||
|
||||
export function main() {
|
||||
describe('ElementBinderBuilder', () => {
|
||||
var evalContext, view, changeDetector;
|
||||
|
||||
function createPipeline({textNodeBindings, propertyBindings, eventBindings, directives, protoElementInjector
|
||||
}={}) {
|
||||
var reflector = new DirectiveMetadataReader();
|
||||
var parser = new Parser(new Lexer());
|
||||
return new CompilePipeline([
|
||||
new MockStep((parent, current, control) => {
|
||||
var hasBinding = false;
|
||||
if (isPresent(current.element.getAttribute('text-binding'))) {
|
||||
MapWrapper.forEach(textNodeBindings, (v,k) => {
|
||||
current.addTextNodeBinding(k, parser.parseBinding(v, null));
|
||||
});
|
||||
hasBinding = true;
|
||||
}
|
||||
if (isPresent(current.element.getAttribute('prop-binding'))) {
|
||||
if (isPresent(propertyBindings)) {
|
||||
MapWrapper.forEach(propertyBindings, (v,k) => {
|
||||
current.addPropertyBinding(k, parser.parseBinding(v, null));
|
||||
});
|
||||
}
|
||||
hasBinding = true;
|
||||
}
|
||||
if (isPresent(current.element.getAttribute('event-binding'))) {
|
||||
MapWrapper.forEach(eventBindings, (v,k) => {
|
||||
current.addEventBinding(k, parser.parseAction(v, null));
|
||||
});
|
||||
hasBinding = true;
|
||||
}
|
||||
if (isPresent(protoElementInjector)) {
|
||||
current.inheritedProtoElementInjector = protoElementInjector;
|
||||
}
|
||||
if (isPresent(current.element.getAttribute('directives'))) {
|
||||
hasBinding = true;
|
||||
for (var i=0; i<directives.length; i++) {
|
||||
var dirMetadata = reflector.read(directives[i]);
|
||||
current.addDirective(dirMetadata);
|
||||
}
|
||||
}
|
||||
if (hasBinding) {
|
||||
current.hasBindings = true;
|
||||
DOM.addClass(current.element, 'ng-binding');
|
||||
}
|
||||
if (isPresent(current.element.getAttribute('viewroot'))) {
|
||||
current.isViewRoot = true;
|
||||
current.inheritedProtoView = new ProtoView(current.element, new DynamicProtoChangeDetector());
|
||||
} else if (isPresent(parent)) {
|
||||
current.inheritedProtoView = parent.inheritedProtoView;
|
||||
}
|
||||
}), new ElementBinderBuilder()
|
||||
]);
|
||||
}
|
||||
|
||||
function instantiateView(protoView) {
|
||||
evalContext = new Context();
|
||||
view = protoView.instantiate(null);
|
||||
view.hydrate(new Injector([]), null, evalContext);
|
||||
changeDetector = view.changeDetector;
|
||||
}
|
||||
|
||||
it('should not create an ElementBinder for elements that have no bindings', () => {
|
||||
var pipeline = createPipeline();
|
||||
var results = pipeline.process(el('<div viewroot><span></span></div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
|
||||
expect(pv.elementBinders.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should create an ElementBinder for elements that have bindings', () => {
|
||||
var pipeline = createPipeline();
|
||||
var results = pipeline.process(el('<div viewroot prop-binding><span prop-binding></span></div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
|
||||
expect(pv.elementBinders.length).toBe(2);
|
||||
expect(pv.elementBinders[1]).not.toBe(pv.elementBinders[0]);
|
||||
});
|
||||
|
||||
it('should inherit ElementBinders to children that have no bindings', () => {
|
||||
var pipeline = createPipeline();
|
||||
var results = pipeline.process(el('<div viewroot prop-binding><span></span></div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
|
||||
expect(pv.elementBinders.length).toBe(1);
|
||||
expect(results[0].inheritedElementBinder).toBe(results[1].inheritedElementBinder);
|
||||
});
|
||||
|
||||
it('should store the current protoElementInjector', () => {
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var protoElementInjector = new ProtoElementInjector(null, 0, directives);
|
||||
|
||||
var pipeline = createPipeline({protoElementInjector: protoElementInjector, directives: directives});
|
||||
var results = pipeline.process(el('<div viewroot directives></div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
|
||||
expect(pv.elementBinders[0].protoElementInjector).toBe(protoElementInjector);
|
||||
});
|
||||
|
||||
it('should store the component directive', () => {
|
||||
var directives = [SomeComponentDirective];
|
||||
var pipeline = createPipeline({protoElementInjector: null, directives: directives});
|
||||
var results = pipeline.process(el('<div viewroot directives></div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
|
||||
expect(pv.elementBinders[0].componentDirective.type).toBe(SomeComponentDirective);
|
||||
});
|
||||
|
||||
it('should store the template directive', () => {
|
||||
var directives = [SomeTemplateDirective];
|
||||
var pipeline = createPipeline({protoElementInjector: null, directives: directives});
|
||||
var results = pipeline.process(el('<div viewroot directives></div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
|
||||
expect(pv.elementBinders[0].templateDirective.type).toBe(SomeTemplateDirective);
|
||||
});
|
||||
|
||||
it('should bind text nodes', () => {
|
||||
var textNodeBindings = MapWrapper.create();
|
||||
MapWrapper.set(textNodeBindings, 0, 'prop1');
|
||||
MapWrapper.set(textNodeBindings, 2, 'prop2');
|
||||
var pipeline = createPipeline({textNodeBindings: textNodeBindings});
|
||||
var results = pipeline.process(el('<div viewroot text-binding>{{}}<span></span>{{}}</div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
|
||||
expect(sortArr(pv.elementBinders[0].textNodeIndices)).toEqual([0, 2]);
|
||||
|
||||
instantiateView(pv);
|
||||
evalContext.prop1 = 'a';
|
||||
evalContext.prop2 = 'b';
|
||||
changeDetector.detectChanges();
|
||||
|
||||
expect(view.nodes[0].childNodes[0].nodeValue).toEqual('a');
|
||||
expect(view.nodes[0].childNodes[2].nodeValue).toEqual('b');
|
||||
});
|
||||
|
||||
it('should bind element properties', () => {
|
||||
var propertyBindings = MapWrapper.createFromStringMap({
|
||||
'value': 'prop1',
|
||||
'hidden': 'prop2'
|
||||
});
|
||||
var pipeline = createPipeline({propertyBindings: propertyBindings});
|
||||
var results = pipeline.process(el('<input viewroot prop-binding>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
|
||||
expect(pv.elementBinders[0].hasElementPropertyBindings).toBe(true);
|
||||
|
||||
instantiateView(pv);
|
||||
evalContext.prop1 = 'a';
|
||||
evalContext.prop2 = false;
|
||||
changeDetector.detectChanges();
|
||||
|
||||
expect(view.nodes[0].value).toEqual('a');
|
||||
expect(view.nodes[0].hidden).toEqual(false);
|
||||
});
|
||||
|
||||
it('should bind class with a dot', () => {
|
||||
var propertyBindings = MapWrapper.createFromStringMap({
|
||||
'class.bar': 'prop1',
|
||||
});
|
||||
var pipeline = createPipeline({propertyBindings: propertyBindings});
|
||||
var results = pipeline.process(el('<input class="foo" viewroot prop-binding>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
|
||||
expect(pv.elementBinders[0].hasElementPropertyBindings).toBe(true);
|
||||
|
||||
instantiateView(pv);
|
||||
|
||||
evalContext.prop1 = true;
|
||||
changeDetector.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('foo ng-binding bar');
|
||||
|
||||
evalContext.prop1 = false;
|
||||
changeDetector.detectChanges();
|
||||
expect(view.nodes[0].className).toEqual('foo ng-binding');
|
||||
});
|
||||
|
||||
it('should bind events', () => {
|
||||
var eventBindings = MapWrapper.createFromStringMap({
|
||||
'event1': '1+1'
|
||||
});
|
||||
var pipeline = createPipeline({eventBindings: eventBindings});
|
||||
var results = pipeline.process(el('<div viewroot event-binding></div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
|
||||
var ast = MapWrapper.get(pv.elementBinders[0].events, 'event1');
|
||||
expect(ast.eval(null)).toBe(2);
|
||||
});
|
||||
|
||||
it('should bind directive properties', () => {
|
||||
var propertyBindings = MapWrapper.createFromStringMap({
|
||||
'boundprop1': 'prop1',
|
||||
'boundprop2': 'prop2',
|
||||
'boundprop3': 'prop3'
|
||||
});
|
||||
var directives = [SomeComponentDirectiveWithBinding,
|
||||
SomeTemplateDirectiveWithBinding,
|
||||
SomeDecoratorDirectiveWith2Bindings];
|
||||
var protoElementInjector = new ProtoElementInjector(null, 0, directives, true);
|
||||
var pipeline = createPipeline({
|
||||
propertyBindings: propertyBindings,
|
||||
directives: directives,
|
||||
protoElementInjector: protoElementInjector
|
||||
});
|
||||
var results = pipeline.process(el('<div viewroot prop-binding directives></div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
results[0].inheritedElementBinder.nestedProtoView = new ProtoView(
|
||||
el('<div></div>'), new DynamicProtoChangeDetector());
|
||||
|
||||
instantiateView(pv);
|
||||
evalContext.prop1 = 'a';
|
||||
evalContext.prop2 = 'b';
|
||||
evalContext.prop3 = 'c';
|
||||
changeDetector.detectChanges();
|
||||
|
||||
expect(view.elementInjectors[0].get(SomeDecoratorDirectiveWith2Bindings).decorProp).toBe('a');
|
||||
expect(view.elementInjectors[0].get(SomeDecoratorDirectiveWith2Bindings).decorProp2).toBe('b');
|
||||
expect(view.elementInjectors[0].get(SomeTemplateDirectiveWithBinding).templProp).toBe('b');
|
||||
expect(view.elementInjectors[0].get(SomeComponentDirectiveWithBinding).compProp).toBe('c');
|
||||
});
|
||||
|
||||
it('should bind directive properties for sibling elements', () => {
|
||||
var propertyBindings = MapWrapper.createFromStringMap({
|
||||
'boundprop1': 'prop1'
|
||||
});
|
||||
var directives = [SomeDecoratorDirectiveWithBinding];
|
||||
var protoElementInjector = new ProtoElementInjector(null, 0, directives);
|
||||
var pipeline = createPipeline({
|
||||
propertyBindings: propertyBindings,
|
||||
directives: directives,
|
||||
protoElementInjector: protoElementInjector
|
||||
});
|
||||
var results = pipeline.process(
|
||||
el('<div viewroot><div prop-binding directives>'+
|
||||
'</div><div prop-binding directives></div></div>'));
|
||||
var pv = results[0].inheritedProtoView;
|
||||
|
||||
instantiateView(pv);
|
||||
evalContext.prop1 = 'a';
|
||||
changeDetector.detectChanges();
|
||||
|
||||
expect(view.elementInjectors[1].get(SomeDecoratorDirectiveWithBinding).decorProp).toBe('a');
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
|
||||
it('should throw if there is no element property bindings for a directive property binding', () => {
|
||||
var pipeline = createPipeline({propertyBindings: MapWrapper.create(), directives: [SomeDecoratorDirectiveWithBinding]});
|
||||
expect( () => {
|
||||
pipeline.process(el('<div viewroot prop-binding directives>'));
|
||||
}).toThrowError("No element binding found for property 'boundprop1' which is required by directive 'SomeDecoratorDirectiveWithBinding'");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Decorator()
|
||||
class SomeDecoratorDirective {
|
||||
}
|
||||
|
||||
@Decorator({
|
||||
bind: {'boundprop1': 'decorProp'}
|
||||
})
|
||||
class SomeDecoratorDirectiveWithBinding {
|
||||
decorProp;
|
||||
decorProp2;
|
||||
constructor() {
|
||||
this.decorProp = null;
|
||||
this.decorProp2 = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Decorator({
|
||||
bind: {
|
||||
'boundprop1': 'decorProp',
|
||||
'boundprop2': 'decorProp2'
|
||||
}
|
||||
})
|
||||
class SomeDecoratorDirectiveWith2Bindings {
|
||||
decorProp;
|
||||
decorProp2;
|
||||
constructor() {
|
||||
this.decorProp = null;
|
||||
this.decorProp2 = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Template()
|
||||
class SomeTemplateDirective {
|
||||
}
|
||||
|
||||
@Template({
|
||||
bind: {'boundprop2': 'templProp'}
|
||||
})
|
||||
class SomeTemplateDirectiveWithBinding {
|
||||
templProp;
|
||||
constructor() {
|
||||
this.templProp = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Component()
|
||||
class SomeComponentDirective {
|
||||
}
|
||||
|
||||
@Component({
|
||||
bind: {'boundprop3': 'compProp'}
|
||||
})
|
||||
class SomeComponentDirectiveWithBinding {
|
||||
compProp;
|
||||
constructor() {
|
||||
this.compProp = null;
|
||||
}
|
||||
}
|
||||
|
||||
class Context {
|
||||
prop1;
|
||||
prop2;
|
||||
prop3;
|
||||
constructor() {
|
||||
this.prop1 = null;
|
||||
this.prop2 = null;
|
||||
this.prop3 = null;
|
||||
}
|
||||
}
|
||||
|
||||
class MockStep extends CompileStep {
|
||||
processClosure:Function;
|
||||
constructor(process) {
|
||||
this.processClosure = process;
|
||||
}
|
||||
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
|
||||
this.processClosure(parent, current, control);
|
||||
}
|
||||
}
|
||||
|
||||
function sortArr(arr) {
|
||||
var arr2 = ListWrapper.clone(arr);
|
||||
arr2.sort();
|
||||
return arr2;
|
||||
}
|
118
modules/angular2/test/core/compiler/pipeline/element_binding_marker_spec.js
vendored
Normal file
118
modules/angular2/test/core/compiler/pipeline/element_binding_marker_spec.js
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'test_lib/test_lib';
|
||||
import {isPresent} from 'facade/src/lang';
|
||||
import {DOM} from 'facade/src/dom';
|
||||
import {MapWrapper} from 'facade/src/collection';
|
||||
|
||||
import {ElementBindingMarker} from 'core/src/compiler/pipeline/element_binding_marker';
|
||||
import {CompilePipeline} from 'core/src/compiler/pipeline/compile_pipeline';
|
||||
import {CompileElement} from 'core/src/compiler/pipeline/compile_element';
|
||||
import {CompileStep} from 'core/src/compiler/pipeline/compile_step'
|
||||
import {CompileControl} from 'core/src/compiler/pipeline/compile_control';
|
||||
import {DirectiveMetadataReader} from 'core/src/compiler/directive_metadata_reader';
|
||||
import {Template, Decorator, Component} from 'core/src/annotations/annotations';
|
||||
|
||||
export function main() {
|
||||
describe('ElementBindingMarker', () => {
|
||||
|
||||
function createPipeline({textNodeBindings, propertyBindings, variableBindings, eventBindings, directives}={}) {
|
||||
var reader = new DirectiveMetadataReader();
|
||||
return new CompilePipeline([
|
||||
new MockStep((parent, current, control) => {
|
||||
if (isPresent(textNodeBindings)) {
|
||||
current.textNodeBindings = textNodeBindings;
|
||||
}
|
||||
if (isPresent(propertyBindings)) {
|
||||
current.propertyBindings = propertyBindings;
|
||||
}
|
||||
if (isPresent(variableBindings)) {
|
||||
current.variableBindings = variableBindings;
|
||||
}
|
||||
if (isPresent(eventBindings)) {
|
||||
current.eventBindings = eventBindings;
|
||||
}
|
||||
if (isPresent(directives)) {
|
||||
for (var i=0; i<directives.length; i++) {
|
||||
current.addDirective(reader.read(directives[i]));
|
||||
}
|
||||
}
|
||||
}), new ElementBindingMarker()
|
||||
]);
|
||||
}
|
||||
|
||||
it('should not mark empty elements', () => {
|
||||
var results = createPipeline().process(el('<div></div>'));
|
||||
assertBinding(results[0], false);
|
||||
});
|
||||
|
||||
it('should mark elements with text node bindings', () => {
|
||||
var textNodeBindings = MapWrapper.create();
|
||||
MapWrapper.set(textNodeBindings, 0, 'expr');
|
||||
var results = createPipeline({textNodeBindings: textNodeBindings}).process(el('<div></div>'));
|
||||
assertBinding(results[0], true);
|
||||
});
|
||||
|
||||
it('should mark elements with property bindings', () => {
|
||||
var propertyBindings = MapWrapper.createFromStringMap({'a': 'expr'});
|
||||
var results = createPipeline({propertyBindings: propertyBindings}).process(el('<div></div>'));
|
||||
assertBinding(results[0], true);
|
||||
});
|
||||
|
||||
it('should mark elements with variable bindings', () => {
|
||||
var variableBindings = MapWrapper.createFromStringMap({'a': 'expr'});
|
||||
var results = createPipeline({variableBindings: variableBindings}).process(el('<div></div>'));
|
||||
assertBinding(results[0], true);
|
||||
});
|
||||
|
||||
it('should mark elements with event bindings', () => {
|
||||
var eventBindings = MapWrapper.createFromStringMap({'click': 'expr'});
|
||||
var results = createPipeline({eventBindings: eventBindings}).process(el('<div></div>'));
|
||||
assertBinding(results[0], true);
|
||||
});
|
||||
|
||||
it('should mark elements with decorator directives', () => {
|
||||
var results = createPipeline({
|
||||
directives: [SomeDecoratorDirective]
|
||||
}).process(el('<div></div>'));
|
||||
assertBinding(results[0], true);
|
||||
});
|
||||
|
||||
it('should mark elements with template directives', () => {
|
||||
var results = createPipeline({
|
||||
directives: [SomeTemplateDirective]
|
||||
}).process(el('<div></div>'));
|
||||
assertBinding(results[0], true);
|
||||
});
|
||||
|
||||
it('should mark elements with component directives', () => {
|
||||
var results = createPipeline({
|
||||
directives: [SomeComponentDirective]
|
||||
}).process(el('<div></div>'));
|
||||
assertBinding(results[0], true);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function assertBinding(pipelineElement, shouldBePresent) {
|
||||
expect(pipelineElement.hasBindings).toBe(shouldBePresent);
|
||||
expect(DOM.hasClass(pipelineElement.element, 'ng-binding')).toBe(shouldBePresent);
|
||||
}
|
||||
|
||||
class MockStep extends CompileStep {
|
||||
processClosure:Function;
|
||||
constructor(process) {
|
||||
this.processClosure = process;
|
||||
}
|
||||
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
|
||||
this.processClosure(parent, current, control);
|
||||
}
|
||||
}
|
||||
|
||||
@Template()
|
||||
class SomeTemplateDirective {}
|
||||
|
||||
@Component()
|
||||
class SomeComponentDirective {}
|
||||
|
||||
@Decorator()
|
||||
class SomeDecoratorDirective {}
|
178
modules/angular2/test/core/compiler/pipeline/pipeline_spec.js
vendored
Normal file
178
modules/angular2/test/core/compiler/pipeline/pipeline_spec.js
vendored
Normal file
@ -0,0 +1,178 @@
|
||||
import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'test_lib/test_lib';
|
||||
import {ListWrapper, List, MapWrapper} from 'facade/src/collection';
|
||||
import {DOM} from 'facade/src/dom';
|
||||
import {isPresent, NumberWrapper, StringWrapper} from 'facade/src/lang';
|
||||
|
||||
import {CompilePipeline} from 'core/src/compiler/pipeline/compile_pipeline';
|
||||
import {CompileElement} from 'core/src/compiler/pipeline/compile_element';
|
||||
import {CompileStep} from 'core/src/compiler/pipeline/compile_step'
|
||||
import {CompileControl} from 'core/src/compiler/pipeline/compile_control';
|
||||
|
||||
export function main() {
|
||||
describe('compile_pipeline', () => {
|
||||
describe('children compilation', () => {
|
||||
it('should walk the tree in depth first order including template contents', () => {
|
||||
var element = el('<div id="1"><template id="2"><span id="3"></span></template></div>');
|
||||
|
||||
var step0Log = [];
|
||||
var results = new CompilePipeline([createLoggerStep(step0Log)]).process(element);
|
||||
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(resultIdLog(results)).toEqual(['1', '2', '3']);
|
||||
});
|
||||
|
||||
it('should stop walking the tree when compileChildren is false', () => {
|
||||
var element = el('<div id="1"><template id="2" ignore-children><span id="3"></span></template></div>');
|
||||
|
||||
var step0Log = [];
|
||||
var pipeline = new CompilePipeline([new IgnoreChildrenStep(), createLoggerStep(step0Log)]);
|
||||
var results = pipeline.process(element);
|
||||
|
||||
expect(step0Log).toEqual(['1', '1<2']);
|
||||
expect(resultIdLog(results)).toEqual(['1', '2']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('control.addParent', () => {
|
||||
it('should report the new parent to the following processor and the result', () => {
|
||||
var element = el('<div id="1"><span wrap0="1" id="2"><b id="3"></b></span></div>');
|
||||
var step0Log = [];
|
||||
var step1Log = [];
|
||||
var pipeline = new CompilePipeline([
|
||||
createWrapperStep('wrap0', step0Log),
|
||||
createLoggerStep(step1Log)
|
||||
]);
|
||||
var result = pipeline.process(element);
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', 'wrap0#0', '2', '3']);
|
||||
});
|
||||
|
||||
it('should allow to add a parent by multiple processors to the same element', () => {
|
||||
var element = el('<div id="1"><span wrap0="1" wrap1="1" id="2"><b id="3"></b></span></div>');
|
||||
var step0Log = [];
|
||||
var step1Log = [];
|
||||
var step2Log = [];
|
||||
var pipeline = new CompilePipeline([
|
||||
createWrapperStep('wrap0', step0Log),
|
||||
createWrapperStep('wrap1', step1Log),
|
||||
createLoggerStep(step2Log)
|
||||
]);
|
||||
var result = pipeline.process(element);
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<3']);
|
||||
expect(step2Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<wrap1#0', 'wrap1#0<2', '2<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', 'wrap0#0', 'wrap1#0', '2', '3']);
|
||||
});
|
||||
|
||||
it('should allow to add a parent by multiple processors to different elements', () => {
|
||||
var element = el('<div id="1"><span wrap0="1" id="2"><b id="3" wrap1="1"></b></span></div>');
|
||||
var step0Log = [];
|
||||
var step1Log = [];
|
||||
var step2Log = [];
|
||||
var pipeline = new CompilePipeline([
|
||||
createWrapperStep('wrap0', step0Log),
|
||||
createWrapperStep('wrap1', step1Log),
|
||||
createLoggerStep(step2Log)
|
||||
]);
|
||||
var result = pipeline.process(element);
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<3']);
|
||||
expect(step2Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<wrap1#0', 'wrap1#0<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', 'wrap0#0', '2', 'wrap1#0', '3']);
|
||||
});
|
||||
|
||||
it('should allow to add multiple parents by the same processor', () => {
|
||||
var element = el('<div id="1"><span wrap0="2" id="2"><b id="3"></b></span></div>');
|
||||
var step0Log = [];
|
||||
var step1Log = [];
|
||||
var pipeline = new CompilePipeline([
|
||||
createWrapperStep('wrap0', step0Log),
|
||||
createLoggerStep(step1Log)
|
||||
]);
|
||||
var result = pipeline.process(element);
|
||||
expect(step0Log).toEqual(['1', '1<2', '2<3']);
|
||||
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<wrap0#1', 'wrap0#1<2', '2<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', 'wrap0#0', 'wrap0#1', '2', '3']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('control.addChild', () => {
|
||||
it('should report the new child to all processors and the result', () => {
|
||||
var element = el('<div id="1"><div id="2"></div></div>');
|
||||
var resultLog = [];
|
||||
var newChild = new CompileElement(el('<div id="3"></div>'));
|
||||
var pipeline = new CompilePipeline([
|
||||
new MockStep((parent, current, control) => {
|
||||
if (StringWrapper.equals(current.element.id, '1')) {
|
||||
control.addChild(newChild);
|
||||
}
|
||||
}),
|
||||
createLoggerStep(resultLog)
|
||||
]);
|
||||
var result = pipeline.process(element);
|
||||
expect(result[2]).toBe(newChild);
|
||||
expect(resultLog).toEqual(['1', '1<2', '1<3']);
|
||||
expect(resultIdLog(result)).toEqual(['1', '2', '3']);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
class MockStep extends CompileStep {
|
||||
processClosure:Function;
|
||||
constructor(process) {
|
||||
this.processClosure = process;
|
||||
}
|
||||
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
|
||||
this.processClosure(parent, current, control);
|
||||
}
|
||||
}
|
||||
|
||||
export class IgnoreChildrenStep extends CompileStep {
|
||||
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
|
||||
var attributeMap = DOM.attributeMap(current.element);
|
||||
if (MapWrapper.contains(attributeMap, 'ignore-children')) {
|
||||
current.compileChildren = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function logEntry(log, parent, current) {
|
||||
var parentId = '';
|
||||
if (isPresent(parent)) {
|
||||
parentId = parent.element.getAttribute('id')+'<';
|
||||
}
|
||||
ListWrapper.push(log, parentId+current.element.getAttribute('id'));
|
||||
}
|
||||
|
||||
function createLoggerStep(log) {
|
||||
return new MockStep((parent, current, control) => {
|
||||
logEntry(log, parent, current);
|
||||
});
|
||||
}
|
||||
|
||||
function createWrapperStep(wrapperId, log) {
|
||||
var nextElementId = 0;
|
||||
return new MockStep((parent, current, control) => {
|
||||
var parentCountStr = current.element.getAttribute(wrapperId);
|
||||
if (isPresent(parentCountStr)) {
|
||||
var parentCount = NumberWrapper.parseInt(parentCountStr, 10);
|
||||
while (parentCount > 0) {
|
||||
control.addParent(new CompileElement(el(`<a id="${wrapperId}#${nextElementId++}"></a>`)));
|
||||
parentCount--;
|
||||
}
|
||||
}
|
||||
logEntry(log, parent, current);
|
||||
});
|
||||
}
|
||||
|
||||
function resultIdLog(result) {
|
||||
var idLog = [];
|
||||
ListWrapper.forEach(result, (current) => {
|
||||
logEntry(idLog, null, current);
|
||||
});
|
||||
return idLog;
|
||||
}
|
57
modules/angular2/test/core/compiler/pipeline/property_binding_parser_spec.js
vendored
Normal file
57
modules/angular2/test/core/compiler/pipeline/property_binding_parser_spec.js
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'test_lib/test_lib';
|
||||
import {PropertyBindingParser} from 'core/src/compiler/pipeline/property_binding_parser';
|
||||
import {CompilePipeline} from 'core/src/compiler/pipeline/compile_pipeline';
|
||||
import {DOM} from 'facade/src/dom';
|
||||
import {MapWrapper} from 'facade/src/collection';
|
||||
|
||||
import {Lexer, Parser} from 'change_detection/change_detection';
|
||||
|
||||
export function main() {
|
||||
describe('PropertyBindingParser', () => {
|
||||
function createPipeline() {
|
||||
return new CompilePipeline([new PropertyBindingParser(new Parser(new Lexer()), null)]);
|
||||
}
|
||||
|
||||
it('should detect [] syntax', () => {
|
||||
var results = createPipeline().process(el('<div [a]="b"></div>'));
|
||||
expect(MapWrapper.get(results[0].propertyBindings, 'a').source).toEqual('b');
|
||||
});
|
||||
|
||||
it('should detect bind- syntax', () => {
|
||||
var results = createPipeline().process(el('<div bind-a="b"></div>'));
|
||||
expect(MapWrapper.get(results[0].propertyBindings, 'a').source).toEqual('b');
|
||||
});
|
||||
|
||||
it('should detect interpolation syntax', () => {
|
||||
// Note: we don't test all corner cases of interpolation as we assume shared functionality between text interpolation
|
||||
// and attribute interpolation.
|
||||
var results = createPipeline().process(el('<div a="{{b}}"></div>'));
|
||||
expect(MapWrapper.get(results[0].propertyBindings, 'a').source).toEqual('{{b}}');
|
||||
});
|
||||
|
||||
it('should detect var- syntax', () => {
|
||||
var results = createPipeline().process(el('<template var-a="b"></template>'));
|
||||
expect(MapWrapper.get(results[0].variableBindings, 'b')).toEqual('a');
|
||||
});
|
||||
|
||||
it('should not allow var- syntax on non template elements', () => {
|
||||
expect( () => {
|
||||
createPipeline().process(el('<div var-a="b"></div>'))
|
||||
}).toThrowError('var-* is only allowed on <template> elements!');
|
||||
});
|
||||
|
||||
it('should detect () syntax', () => {
|
||||
var results = createPipeline().process(el('<div (click)="b()"></div>'));
|
||||
expect(MapWrapper.get(results[0].eventBindings, 'click').source).toEqual('b()');
|
||||
// "(click[])" is not an expected syntax and is only used to validate the regexp
|
||||
results = createPipeline().process(el('<div (click[])="b()"></div>'));
|
||||
expect(MapWrapper.get(results[0].eventBindings, 'click[]').source).toEqual('b()');
|
||||
|
||||
});
|
||||
|
||||
it('should detect on- syntax', () => {
|
||||
var results = createPipeline().process(el('<div on-click="b()"></div>'));
|
||||
expect(MapWrapper.get(results[0].eventBindings, 'click').source).toEqual('b()');
|
||||
});
|
||||
});
|
||||
}
|
180
modules/angular2/test/core/compiler/pipeline/proto_element_injector_builder_spec.js
vendored
Normal file
180
modules/angular2/test/core/compiler/pipeline/proto_element_injector_builder_spec.js
vendored
Normal file
@ -0,0 +1,180 @@
|
||||
import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'test_lib/test_lib';
|
||||
import {isPresent, isBlank} from 'facade/src/lang';
|
||||
import {DOM} from 'facade/src/dom';
|
||||
import {List, ListWrapper} from 'facade/src/collection';
|
||||
|
||||
import {ProtoElementInjectorBuilder} from 'core/src/compiler/pipeline/proto_element_injector_builder';
|
||||
import {CompilePipeline} from 'core/src/compiler/pipeline/compile_pipeline';
|
||||
import {CompileElement} from 'core/src/compiler/pipeline/compile_element';
|
||||
import {CompileStep} from 'core/src/compiler/pipeline/compile_step'
|
||||
import {CompileControl} from 'core/src/compiler/pipeline/compile_control';
|
||||
import {ProtoView} from 'core/src/compiler/view';
|
||||
import {DirectiveMetadataReader} from 'core/src/compiler/directive_metadata_reader';
|
||||
import {Template, Decorator, Component} from 'core/src/annotations/annotations';
|
||||
import {ProtoElementInjector} from 'core/src/compiler/element_injector';
|
||||
|
||||
export function main() {
|
||||
describe('ProtoElementInjectorBuilder', () => {
|
||||
var protoElementInjectorBuilder, protoView;
|
||||
beforeEach( () => {
|
||||
protoElementInjectorBuilder = new TestableProtoElementInjectorBuilder();
|
||||
protoView = new ProtoView(null, null);
|
||||
});
|
||||
|
||||
function createPipeline(directives = null) {
|
||||
if (isBlank(directives)) {
|
||||
directives = [];
|
||||
}
|
||||
var reader = new DirectiveMetadataReader();
|
||||
return new CompilePipeline([new MockStep((parent, current, control) => {
|
||||
if (isPresent(current.element.getAttribute('viewroot'))) {
|
||||
current.isViewRoot = true;
|
||||
}
|
||||
if (isPresent(current.element.getAttribute('directives'))) {
|
||||
for (var i=0; i<directives.length; i++) {
|
||||
var dirMetadata = reader.read(directives[i]);
|
||||
current.addDirective(dirMetadata);
|
||||
}
|
||||
}
|
||||
current.inheritedProtoView = protoView;
|
||||
}), protoElementInjectorBuilder]);
|
||||
}
|
||||
|
||||
function getCreationArgs(protoElementInjector) {
|
||||
return protoElementInjectorBuilder.findArgsFor(protoElementInjector);
|
||||
}
|
||||
|
||||
it('should not create a ProtoElementInjector for elements without directives', () => {
|
||||
var results = createPipeline().process(el('<div></div>'));
|
||||
expect(results[0].inheritedProtoElementInjector).toBe(null);
|
||||
});
|
||||
|
||||
it('should create a ProtoElementInjector for elements directives', () => {
|
||||
var directives = [SomeComponentDirective, SomeTemplateDirective, SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(el('<div directives></div>'));
|
||||
var creationArgs = getCreationArgs(results[0].inheritedProtoElementInjector);
|
||||
var boundDirectives = creationArgs['bindings'].map((b) => b.key.token);
|
||||
expect(boundDirectives).toEqual(directives);
|
||||
});
|
||||
|
||||
it('should mark ProtoElementInjector for elements with component directives and use the ComponentDirective as first binding', () => {
|
||||
var directives = [SomeDecoratorDirective, SomeComponentDirective];
|
||||
var results = createPipeline(directives).process(el('<div directives></div>'));
|
||||
var creationArgs = getCreationArgs(results[0].inheritedProtoElementInjector);
|
||||
expect(creationArgs['firstBindingIsComponent']).toBe(true);
|
||||
var boundDirectives = creationArgs['bindings'].map((b) => b.key.token);
|
||||
expect(boundDirectives).toEqual([SomeComponentDirective, SomeDecoratorDirective]);
|
||||
});
|
||||
|
||||
it('should use the next ElementBinder index as index of the ProtoElementInjector', () => {
|
||||
// just adding some indices..
|
||||
ListWrapper.push(protoView.elementBinders, null);
|
||||
ListWrapper.push(protoView.elementBinders, null);
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(el('<div directives></div>'));
|
||||
var creationArgs = getCreationArgs(results[0].inheritedProtoElementInjector);
|
||||
expect(creationArgs['index']).toBe(protoView.elementBinders.length);
|
||||
});
|
||||
|
||||
describe("inheritedProtoElementInjector", () => {
|
||||
it('should inherit the ProtoElementInjector down to children without directives', () => {
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(el('<div directives><span></span></div>'));
|
||||
expect(results[1].inheritedProtoElementInjector).toBe(results[0].inheritedProtoElementInjector);
|
||||
});
|
||||
|
||||
it('should use the ProtoElementInjector of the parent element as parent', () => {
|
||||
var element = el('<div directives><span><a directives></a></span></div>');
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(element);
|
||||
expect(results[2].inheritedProtoElementInjector.parent).toBe(
|
||||
results[0].inheritedProtoElementInjector);
|
||||
});
|
||||
|
||||
it('should use a null parent for viewRoots', () => {
|
||||
var element = el('<div directives><span viewroot directives></span></div>');
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(element);
|
||||
expect(results[1].inheritedProtoElementInjector.parent).toBe(null);
|
||||
});
|
||||
|
||||
it('should use a null parent if there is an intermediate viewRoot', () => {
|
||||
var element = el('<div directives><span viewroot><a directives></a></span></div>');
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(element);
|
||||
expect(results[2].inheritedProtoElementInjector.parent).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("distanceToParentInjector", () => {
|
||||
it("should be 0 for root elements", () => {
|
||||
var element = el('<div directives></div>');
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(element);
|
||||
expect(results[0].inheritedProtoElementInjector.distanceToParent).toBe(0);
|
||||
});
|
||||
|
||||
it("should be 1 when a parent element has an injector", () => {
|
||||
var element = el('<div directives><span directives></span></div>');
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(element);
|
||||
expect(results[1].inheritedProtoElementInjector.distanceToParent).toBe(1);
|
||||
});
|
||||
|
||||
it("should add 1 for every element that does not have an injector", () => {
|
||||
var element = el('<div directives><a><b><span directives></span></b></a></div>');
|
||||
var directives = [SomeDecoratorDirective];
|
||||
var results = createPipeline(directives).process(element);
|
||||
expect(results[3].inheritedProtoElementInjector.distanceToParent).toBe(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
class TestableProtoElementInjectorBuilder extends ProtoElementInjectorBuilder {
|
||||
debugObjects:List;
|
||||
|
||||
constructor() {
|
||||
this.debugObjects = [];
|
||||
}
|
||||
|
||||
findArgsFor(protoElementInjector:ProtoElementInjector) {
|
||||
for (var i=0; i<this.debugObjects.length; i+=2) {
|
||||
if (this.debugObjects[i] === protoElementInjector) {
|
||||
return this.debugObjects[i+1];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internalCreateProtoElementInjector(parent, index, bindings, firstBindingIsComponent, distance) {
|
||||
var result = new ProtoElementInjector(parent, index, bindings, firstBindingIsComponent, distance);
|
||||
ListWrapper.push(this.debugObjects, result);
|
||||
ListWrapper.push(this.debugObjects, {'parent': parent, 'index': index, 'bindings': bindings, 'firstBindingIsComponent': firstBindingIsComponent});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class MockStep extends CompileStep {
|
||||
processClosure:Function;
|
||||
constructor(process) {
|
||||
this.processClosure = process;
|
||||
}
|
||||
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
|
||||
this.processClosure(parent, current, control);
|
||||
}
|
||||
}
|
||||
|
||||
class SomeComponentService {}
|
||||
|
||||
@Template()
|
||||
class SomeTemplateDirective {}
|
||||
|
||||
@Component({
|
||||
componentServices: [SomeComponentService]
|
||||
})
|
||||
class SomeComponentDirective {}
|
||||
|
||||
@Decorator()
|
||||
class SomeDecoratorDirective {}
|
86
modules/angular2/test/core/compiler/pipeline/proto_view_builder_spec.js
vendored
Normal file
86
modules/angular2/test/core/compiler/pipeline/proto_view_builder_spec.js
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'test_lib/test_lib';
|
||||
import {isPresent} from 'facade/src/lang';
|
||||
import {dynamicChangeDetection} from 'change_detection/change_detection';
|
||||
import {ElementBinder} from 'core/src/compiler/element_binder';
|
||||
import {ProtoViewBuilder} from 'core/src/compiler/pipeline/proto_view_builder';
|
||||
import {CompilePipeline} from 'core/src/compiler/pipeline/compile_pipeline';
|
||||
import {CompileElement} from 'core/src/compiler/pipeline/compile_element';
|
||||
import {CompileStep} from 'core/src/compiler/pipeline/compile_step'
|
||||
import {CompileControl} from 'core/src/compiler/pipeline/compile_control';
|
||||
import {DOM} from 'facade/src/dom';
|
||||
import {MapWrapper} from 'facade/src/collection';
|
||||
|
||||
export function main() {
|
||||
describe('ProtoViewBuilder', () => {
|
||||
function createPipeline(variableBindings=null) {
|
||||
return new CompilePipeline([new MockStep((parent, current, control) => {
|
||||
if (isPresent(current.element.getAttribute('viewroot'))) {
|
||||
current.isViewRoot = true;
|
||||
}
|
||||
if (isPresent(current.element.getAttribute('var-binding'))) {
|
||||
current.variableBindings = MapWrapper.createFromStringMap(variableBindings);
|
||||
}
|
||||
current.inheritedElementBinder = new ElementBinder(null, null, null);
|
||||
}), new ProtoViewBuilder(dynamicChangeDetection)]);
|
||||
}
|
||||
|
||||
it('should not create a ProtoView when the isViewRoot flag is not set', () => {
|
||||
var results = createPipeline().process(el('<div></div>'));
|
||||
expect(results[0].inheritedProtoView).toBe(null);
|
||||
});
|
||||
|
||||
it('should create a ProtoView when the isViewRoot flag is set', () => {
|
||||
var viewRootElement = el('<div viewroot></div>');
|
||||
var results = createPipeline().process(viewRootElement);
|
||||
expect(results[0].inheritedProtoView.element).toBe(viewRootElement);
|
||||
});
|
||||
|
||||
it('should inherit the ProtoView down to children that have no isViewRoot set', () => {
|
||||
var viewRootElement = el('<div viewroot><span></span></div>');
|
||||
var results = createPipeline().process(viewRootElement);
|
||||
expect(results[0].inheritedProtoView.element).toBe(viewRootElement);
|
||||
expect(results[1].inheritedProtoView.element).toBe(viewRootElement);
|
||||
});
|
||||
|
||||
it('should save ProtoView into the elementBinder of parent element', () => {
|
||||
var element = el('<div viewroot><template><a viewroot></a></template></div>');
|
||||
var results = createPipeline().process(element);
|
||||
expect(results[1].inheritedElementBinder.nestedProtoView).toBe(results[2].inheritedProtoView);
|
||||
});
|
||||
|
||||
it('should bind variables to the nested ProtoView', () => {
|
||||
var element = el('<div viewroot><template var-binding><a viewroot></a></template></div>');
|
||||
var results = createPipeline({
|
||||
'var1': 'map1',
|
||||
'var2': 'map2'
|
||||
}).process(element);
|
||||
var npv = results[1].inheritedElementBinder.nestedProtoView;
|
||||
expect(npv.variableBindings).toEqual(MapWrapper.createFromStringMap({
|
||||
'var1': 'map1',
|
||||
'var2': 'map2'
|
||||
}));
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
|
||||
it('should not allow multiple nested ProtoViews for the same parent element', () => {
|
||||
var element = el('<div viewroot><template><a viewroot></a><a viewroot></a></template></div>');
|
||||
expect( () => {
|
||||
createPipeline().process(element);
|
||||
}).toThrowError('Only one nested view per element is allowed');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
class MockStep extends CompileStep {
|
||||
processClosure:Function;
|
||||
constructor(process) {
|
||||
this.processClosure = process;
|
||||
}
|
||||
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
|
||||
this.processClosure(parent, current, control);
|
||||
}
|
||||
}
|
57
modules/angular2/test/core/compiler/pipeline/text_interpolation_parser_spec.js
vendored
Normal file
57
modules/angular2/test/core/compiler/pipeline/text_interpolation_parser_spec.js
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
import {describe, beforeEach, expect, it, iit, ddescribe, el} from 'test_lib/test_lib';
|
||||
import {TextInterpolationParser} from 'core/src/compiler/pipeline/text_interpolation_parser';
|
||||
import {CompilePipeline} from 'core/src/compiler/pipeline/compile_pipeline';
|
||||
import {DOM} from 'facade/src/dom';
|
||||
import {MapWrapper} from 'facade/src/collection';
|
||||
|
||||
import {Lexer, Parser} from 'change_detection/change_detection';
|
||||
import {IgnoreChildrenStep} from './pipeline_spec';
|
||||
|
||||
export function main() {
|
||||
describe('TextInterpolationParser', () => {
|
||||
function createPipeline() {
|
||||
return new CompilePipeline([
|
||||
new IgnoreChildrenStep(),
|
||||
new TextInterpolationParser(new Parser(new Lexer()), null)
|
||||
]);
|
||||
}
|
||||
|
||||
it('should find text interpolation in normal elements', () => {
|
||||
var results = createPipeline().process(el('<div>{{expr1}}<span></span>{{expr2}}</div>'));
|
||||
var bindings = results[0].textNodeBindings;
|
||||
expect(MapWrapper.get(bindings, 0).source).toEqual("{{expr1}}");
|
||||
expect(MapWrapper.get(bindings, 2).source).toEqual("{{expr2}}");
|
||||
});
|
||||
|
||||
it('should find text interpolation in template elements', () => {
|
||||
var results = createPipeline().process(el('<template>{{expr1}}<span></span>{{expr2}}</template>'));
|
||||
var bindings = results[0].textNodeBindings;
|
||||
expect(MapWrapper.get(bindings, 0).source).toEqual("{{expr1}}");
|
||||
expect(MapWrapper.get(bindings, 2).source).toEqual("{{expr2}}");
|
||||
});
|
||||
|
||||
it('should allow multiple expressions', () => {
|
||||
var results = createPipeline().process(el('<div>{{expr1}}{{expr2}}</div>'));
|
||||
var bindings = results[0].textNodeBindings;
|
||||
expect(MapWrapper.get(bindings, 0).source).toEqual("{{expr1}}{{expr2}}");
|
||||
});
|
||||
|
||||
it('should not interpolate when compileChildren is false', () => {
|
||||
var results = createPipeline().process(el('<div>{{included}}<span ignore-children>{{excluded}}</span></div>'));
|
||||
var bindings = results[0].textNodeBindings;
|
||||
expect(MapWrapper.get(bindings, 0).source).toEqual("{{included}}");
|
||||
expect(results[1].textNodeBindings).toBe(null);
|
||||
});
|
||||
|
||||
it('should allow fixed text before, in between and after expressions', () => {
|
||||
var results = createPipeline().process(el('<div>a{{expr1}}b{{expr2}}c</div>'));
|
||||
var bindings = results[0].textNodeBindings;
|
||||
expect(MapWrapper.get(bindings, 0).source).toEqual("a{{expr1}}b{{expr2}}c");
|
||||
});
|
||||
|
||||
it('should escape quotes in fixed parts', () => {
|
||||
var results = createPipeline().process(el("<div>'\"a{{expr1}}</div>"));
|
||||
expect(MapWrapper.get(results[0].textNodeBindings, 0).source).toEqual("'\"a{{expr1}}");
|
||||
});
|
||||
});
|
||||
}
|
177
modules/angular2/test/core/compiler/pipeline/view_splitter_spec.js
vendored
Normal file
177
modules/angular2/test/core/compiler/pipeline/view_splitter_spec.js
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'test_lib/test_lib';
|
||||
import {isPresent} from 'facade/src/lang';
|
||||
import {MapWrapper} from 'facade/src/collection';
|
||||
|
||||
import {ViewSplitter} from 'core/src/compiler/pipeline/view_splitter';
|
||||
import {CompilePipeline} from 'core/src/compiler/pipeline/compile_pipeline';
|
||||
import {DOM, TemplateElement} from 'facade/src/dom';
|
||||
|
||||
import {Lexer, Parser} from 'change_detection/change_detection';
|
||||
|
||||
export function main() {
|
||||
describe('ViewSplitter', () => {
|
||||
|
||||
function createPipeline() {
|
||||
return new CompilePipeline([new ViewSplitter(new Parser(new Lexer()), null)]);
|
||||
}
|
||||
|
||||
it('should mark root elements as viewRoot', () => {
|
||||
var rootElement = el('<div></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(results[0].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
describe('<template> elements', () => {
|
||||
|
||||
it('should move the content into a new <template> element and mark that as viewRoot', () => {
|
||||
var rootElement = el('<div><template if="true">a</template></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(DOM.getOuterHTML(results[1].element)).toEqual('<template if="true"></template>');
|
||||
expect(results[1].isViewRoot).toBe(false);
|
||||
expect(DOM.getOuterHTML(results[2].element)).toEqual('<template>a</template>');
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
it('should not wrap a root <template> element', () => {
|
||||
var rootElement = el('<div></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(results.length).toBe(1);
|
||||
expect(DOM.getOuterHTML(rootElement)).toEqual('<div></div>');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('elements with template attribute', () => {
|
||||
|
||||
it('should replace the element with an empty <template> element', () => {
|
||||
var rootElement = el('<div><span template=""></span></div>');
|
||||
var originalChild = rootElement.childNodes[0];
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(results[0].element).toBe(rootElement);
|
||||
expect(DOM.getOuterHTML(results[0].element)).toEqual('<div><template></template></div>');
|
||||
expect(DOM.getOuterHTML(results[2].element)).toEqual('<span template=""></span>')
|
||||
expect(results[2].element).toBe(originalChild);
|
||||
});
|
||||
|
||||
it('should mark the element as viewRoot', () => {
|
||||
var rootElement = el('<div><div template></div></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
it('should work with top-level template node', () => {
|
||||
var rootElement = DOM.createTemplate('<div template>x</div>');
|
||||
var originalChild = rootElement.content.childNodes[0];
|
||||
var results = createPipeline().process(rootElement);
|
||||
|
||||
expect(results[0].element).toBe(rootElement);
|
||||
expect(results[0].isViewRoot).toBe(true);
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
expect(DOM.getOuterHTML(results[0].element)).toEqual('<template><template></template></template>');
|
||||
expect(results[2].element).toBe(originalChild);
|
||||
});
|
||||
|
||||
it('should add property bindings from the template attribute', () => {
|
||||
var rootElement = el('<div><div template="prop:expr"></div></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(MapWrapper.get(results[1].propertyBindings, 'prop').source).toEqual('expr');
|
||||
});
|
||||
|
||||
it('should add variable mappings from the template attribute', () => {
|
||||
var rootElement = el('<div><div template="var varName=mapName"></div></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(results[1].variableBindings).toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
|
||||
});
|
||||
|
||||
it('should add entries without value as attribute to the element', () => {
|
||||
var rootElement = el('<div><div template="varname"></div></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(results[1].attrs()).toEqual(MapWrapper.createFromStringMap({'varname': ''}));
|
||||
expect(results[1].propertyBindings).toBe(null);
|
||||
expect(results[1].variableBindings).toBe(null);
|
||||
});
|
||||
|
||||
it('should iterate properly after a template dom modification', () => {
|
||||
var rootElement = el('<div><div template></div><after></after></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
// 1 root + 2 initial + 1 generated template elements
|
||||
expect(results.length).toEqual(4);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('elements with !directive_name attribute', () => {
|
||||
|
||||
it('should replace the element with an empty <template> element', () => {
|
||||
var rootElement = el('<div><span !if></span></div>');
|
||||
var originalChild = rootElement.childNodes[0];
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(results[0].element).toBe(rootElement);
|
||||
expect(DOM.getOuterHTML(results[0].element)).toEqual('<div><template if=""></template></div>');
|
||||
expect(DOM.getOuterHTML(results[2].element)).toEqual('<span !if=""></span>')
|
||||
expect(results[2].element).toBe(originalChild);
|
||||
});
|
||||
|
||||
it('should mark the element as viewRoot', () => {
|
||||
var rootElement = el('<div><div !foo="bar"></div></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
});
|
||||
|
||||
it('should work with top-level template node', () => {
|
||||
var rootElement = DOM.createTemplate('<div !foo>x</div>');
|
||||
var originalChild = rootElement.content.childNodes[0];
|
||||
var results = createPipeline().process(rootElement);
|
||||
|
||||
expect(results[0].element).toBe(rootElement);
|
||||
expect(results[0].isViewRoot).toBe(true);
|
||||
expect(results[2].isViewRoot).toBe(true);
|
||||
expect(DOM.getOuterHTML(results[0].element)).toEqual('<template><template foo=""></template></template>');
|
||||
expect(results[2].element).toBe(originalChild);
|
||||
});
|
||||
|
||||
it('should add property bindings from the template attribute', () => {
|
||||
var rootElement = el('<div><div !prop="expr"></div></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(MapWrapper.get(results[1].propertyBindings, 'prop').source).toEqual('expr');
|
||||
});
|
||||
|
||||
it('should add variable mappings from the template attribute', () => {
|
||||
var rootElement = el('<div><div !foreach="var varName=mapName"></div></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(results[1].variableBindings).toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
|
||||
});
|
||||
|
||||
it('should add entries without value as attribute to the element', () => {
|
||||
var rootElement = el('<div><div !varname></div></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
expect(results[1].attrs()).toEqual(MapWrapper.createFromStringMap({'varname': ''}));
|
||||
expect(results[1].propertyBindings).toBe(null);
|
||||
expect(results[1].variableBindings).toBe(null);
|
||||
});
|
||||
|
||||
it('should iterate properly after a template dom modification', () => {
|
||||
var rootElement = el('<div><div !foo></div><after></after></div>');
|
||||
var results = createPipeline().process(rootElement);
|
||||
// 1 root + 2 initial + 1 generated template elements
|
||||
expect(results.length).toEqual(4);
|
||||
});
|
||||
|
||||
it('should not allow multiple template directives on the same element', () => {
|
||||
expect( () => {
|
||||
var rootElement = el('<div><div !foo !bar="blah"></div></div>');
|
||||
createPipeline().process(rootElement);
|
||||
}).toThrowError('Only one template directive per element is allowed: foo and bar cannot be used simultaneously!');
|
||||
});
|
||||
|
||||
it('should not allow template and bang directives on the same element', () => {
|
||||
expect( () => {
|
||||
var rootElement = el('<div><div !foo template="blah"></div></div>');
|
||||
createPipeline().process(rootElement);
|
||||
}).toThrowError('Only one template directive per element is allowed: blah and foo cannot be used simultaneously!');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user