import {describe, beforeEach, it, xit, expect, iit, ddescribe, el} from 'angular2/test_lib'; import {isPresent, assertionsEnabled} from 'angular2/src/facade/lang'; import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; import {DirectiveParser} from 'angular2/src/render/dom/compiler/directive_parser'; import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline'; import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step'; import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element'; import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control'; import {ViewDefinition, DirectiveMetadata} from 'angular2/src/render/api'; import {Lexer, Parser} from 'angular2/change_detection'; export function main() { describe('DirectiveParser', () => { var parser, annotatedDirectives; beforeEach( () => { annotatedDirectives = [ someComponent, someComponent2, someComponent3, someViewport, someViewport2, someDecorator, someDecoratorIgnoringChildren, someDecoratorWithProps, someDecoratorWithEvents ]; parser = new Parser(new Lexer()); }); function createPipeline(propertyBindings = null) { return new CompilePipeline([ new MockStep( (parent, current, control) => { if (isPresent(propertyBindings)) { StringMapWrapper.forEach(propertyBindings, (ast, name) => { current.bindElement().bindProperty(name, ast); }); } }), new DirectiveParser(parser, annotatedDirectives) ]); } function process(el, propertyBindings = null) { var pipeline = createPipeline(propertyBindings); return ListWrapper.map(pipeline.process(el), (ce) => ce.inheritedElementBinder ); } it('should not add directives if they are not used', () => { var results = process(el('<div></div>')); expect(results[0]).toBe(null); }); it('should detect directives in attributes', () => { var results = process(el('<div some-decor></div>')); expect(results[0].directives[0].directiveIndex).toBe( annotatedDirectives.indexOf(someDecorator) ); }); it('should detect directives with multiple attributes', () => { var results = process(el('<input type=text control=one></input>')); expect(results[0].directives[0].directiveIndex).toBe( annotatedDirectives.indexOf(someComponent3) ); }); 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 directive config', () => { var results = createPipeline().process(el('<div some-decor-ignoring-children></div>')); expect(results[0].compileChildren).toEqual(false); }); it('should bind directive properties from bound properties', () => { var results = process( el('<div some-decor-props></div>'), { 'elProp': parser.parseBinding('someExpr', '') } ); var directiveBinding = results[0].directives[0]; expect(MapWrapper.get(directiveBinding.propertyBindings, 'dirProp').source) .toEqual('someExpr'); }); it('should bind directive properties with pipes', () => { var results = process( el('<div some-decor-props></div>'), { 'elProp': parser.parseBinding('someExpr', '') } ); var directiveBinding = results[0].directives[0]; var pipedProp = MapWrapper.get(directiveBinding.propertyBindings, 'doubleProp'); var simpleProp = MapWrapper.get(directiveBinding.propertyBindings, 'dirProp'); expect(pipedProp.ast.name).toEqual('double'); expect(pipedProp.ast.exp).toEqual(simpleProp.ast); expect(simpleProp.source).toEqual('someExpr'); }); it('should bind directive properties from attribute values', () => { var results = process( el('<div some-decor-props el-prop="someValue"></div>') ); var directiveBinding = results[0].directives[0]; var simpleProp = MapWrapper.get(directiveBinding.propertyBindings, 'dirProp'); expect(simpleProp.source).toEqual('someValue'); }); it('should store working property setters', () => { var element = el('<input some-decor-props>'); var results = process(element); var setter = MapWrapper.get(results[0].propertySetters, 'value'); setter(element, 'abc'); expect(element.value).toEqual('abc'); }); it('should read attribute values', () => { var element = el('<input some-decor-props some-attr="someValue">'); var results = process(element); expect(MapWrapper.get(results[0].readAttributes, 'some-attr')).toEqual('someValue'); }); it('should bind directive events', () => { var results = process( el('<div some-decor-events></div>') ); var directiveBinding = results[0].directives[0]; expect(MapWrapper.get(directiveBinding.eventBindings, 'click').source) .toEqual('doIt()'); }); describe('viewport directives', () => { it('should not allow multiple viewport directives on the same element', () => { expect( () => { process( el('<template some-vp some-vp2></template>') ); }).toThrowError('Only one viewport directive is allowed per element - check <template some-vp some-vp2>'); }); it('should not allow viewport directives on non <template> elements', () => { expect( () => { process( el('<div some-vp></div>') ); }).toThrowError('Viewport directives need to be placed on <template> elements or elements with template attribute - check <div some-vp>'); }); }); describe('component directives', () => { it('should save the component id', () => { var results = process( el('<div some-comp></div>') ); expect(results[0].componentId).toEqual('someComponent'); }); it('should not allow multiple component directives on the same element', () => { expect( () => { process( el('<div some-comp some-comp2></div>') ); }).toThrowError('Only one component directive is allowed per element - check <div some-comp some-comp2>'); }); it('should not allow component directives on <template> elements', () => { expect( () => { process( el('<template some-comp></template>') ); }).toThrowError('Only template directives are allowed on template elements - check <template some-comp>'); }); }); }); } class MockStep extends CompileStep { processClosure:Function; constructor(process) { super(); this.processClosure = process; } process(parent:CompileElement, current:CompileElement, control:CompileControl) { this.processClosure(parent, current, control); } } var someComponent = new DirectiveMetadata({ selector: '[some-comp]', id: 'someComponent', type: DirectiveMetadata.COMPONENT_TYPE }); var someComponent2 = new DirectiveMetadata({ selector: '[some-comp2]', id: 'someComponent2', type: DirectiveMetadata.COMPONENT_TYPE }); var someComponent3 = new DirectiveMetadata({ selector: 'input[type=text][control]', id: 'someComponent3', type: DirectiveMetadata.COMPONENT_TYPE }); var someViewport = new DirectiveMetadata({ selector: '[some-vp]', id: 'someViewport', type: DirectiveMetadata.VIEWPORT_TYPE }); var someViewport2 = new DirectiveMetadata({ selector: '[some-vp2]', id: 'someViewport2', type: DirectiveMetadata.VIEWPORT_TYPE }); var someDecorator = new DirectiveMetadata({ selector: '[some-decor]' }); var someDecoratorIgnoringChildren = new DirectiveMetadata({ selector: '[some-decor-ignoring-children]', compileChildren: false }); var someDecoratorWithProps = new DirectiveMetadata({ selector: '[some-decor-props]', properties: MapWrapper.createFromStringMap({ 'dirProp': 'elProp', 'doubleProp': 'elProp | double' }), setters: ['value'], readAttributes: ['some-attr'] }); var someDecoratorWithEvents = new DirectiveMetadata({ selector: '[some-decor-events]', hostListeners: MapWrapper.createFromStringMap({ 'click': 'doIt()' }) });