Also consolidates metadata handling in `ElementInjector` BREAKING CHANGE: - renames `DirectiveMetadataReader` into `DirectiveResolver` and removes `src/core/compiler/directive_metadata`. Fixes #1712 Fixes #1713
		
			
				
	
	
		
			231 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			231 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import {
 | |
|   AsyncTestCompleter,
 | |
|   beforeEach,
 | |
|   ddescribe,
 | |
|   describe,
 | |
|   el,
 | |
|   expect,
 | |
|   iit,
 | |
|   inject,
 | |
|   IS_DARTIUM,
 | |
|   it,
 | |
| } from 'angular2/test_lib';
 | |
| 
 | |
| import {DOM} from 'angular2/src/dom/dom_adapter';
 | |
| import {List, ListWrapper, Map, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
 | |
| import {Type, isBlank, stringify, isPresent} from 'angular2/src/facade/lang';
 | |
| import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
 | |
| 
 | |
| import {DomCompiler} from 'angular2/src/render/dom/compiler/compiler';
 | |
| import {ProtoViewDto, ViewDefinition, DirectiveMetadata} from 'angular2/src/render/api';
 | |
| import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
 | |
| import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step'
 | |
| import {CompileStepFactory} from 'angular2/src/render/dom/compiler/compile_step_factory';
 | |
| import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control';
 | |
| import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
 | |
| 
 | |
| import {UrlResolver} from 'angular2/src/services/url_resolver';
 | |
| 
 | |
| import {resolveInternalDomProtoView} from 'angular2/src/render/dom/view/proto_view';
 | |
| 
 | |
| export function runCompilerCommonTests() {
 | |
|   describe('DomCompiler', function() {
 | |
|     var mockStepFactory;
 | |
| 
 | |
|     function createCompiler(processClosure, urlData = null) {
 | |
|       if (isBlank(urlData)) {
 | |
|         urlData = MapWrapper.create();
 | |
|       }
 | |
|       var tplLoader =  new FakeTemplateLoader(urlData);
 | |
|       mockStepFactory = new MockStepFactory([new MockStep(processClosure)]);
 | |
|       return new DomCompiler(mockStepFactory, tplLoader);
 | |
|     }
 | |
| 
 | |
|     describe('compile', () => {
 | |
| 
 | |
|       it('should run the steps and build the AppProtoView of the root element', inject([AsyncTestCompleter], (async) => {
 | |
|         var compiler = createCompiler((parent, current, control) => {
 | |
|           current.inheritedProtoView.bindVariable('b', 'a');
 | |
|         });
 | |
|         compiler.compile(new ViewDefinition({
 | |
|           componentId: 'someComponent',
 | |
|           template: '<div></div>'
 | |
|         })).then( (protoView) => {
 | |
|           expect(protoView.variableBindings).toEqual(MapWrapper.createFromStringMap({
 | |
|             'a': 'b'
 | |
|           }));
 | |
|           async.done();
 | |
|         });
 | |
|       }));
 | |
| 
 | |
|       it('should run the steps and build the proto view', inject([AsyncTestCompleter], (async) => {
 | |
|         var compiler = createCompiler((parent, current, control) => {
 | |
|           current.inheritedProtoView.bindVariable('b', 'a');
 | |
|         });
 | |
| 
 | |
|         var dirMetadata = new DirectiveMetadata({id: 'id', selector: 'CUSTOM', type: DirectiveMetadata.COMPONENT_TYPE});
 | |
|         compiler.compileHost(dirMetadata).then( (protoView) => {
 | |
|           expect(DOM.tagName(resolveInternalDomProtoView(protoView.render).element)).toEqual('CUSTOM')
 | |
|           expect(mockStepFactory.viewDef.directives).toEqual([dirMetadata]);
 | |
|           expect(protoView.variableBindings).toEqual(MapWrapper.createFromStringMap({
 | |
|             'a': 'b'
 | |
|           }));
 | |
|           async.done();
 | |
|         });
 | |
|       }));
 | |
| 
 | |
|       it('should use the inline template and compile in sync', inject([AsyncTestCompleter], (async) => {
 | |
|         var compiler = createCompiler(EMPTY_STEP);
 | |
|         compiler.compile(new ViewDefinition({
 | |
|           componentId: 'someId',
 | |
|           template: 'inline component'
 | |
|         })).then( (protoView) => {
 | |
|           expect(DOM.getInnerHTML(resolveInternalDomProtoView(protoView.render).element)).toEqual('inline component');
 | |
|           async.done();
 | |
|         });
 | |
|       }));
 | |
| 
 | |
|       it('should load url templates', inject([AsyncTestCompleter], (async) => {
 | |
|         var urlData = MapWrapper.createFromStringMap({
 | |
|           'someUrl': 'url component'
 | |
|         });
 | |
|         var compiler = createCompiler(EMPTY_STEP, urlData);
 | |
|         compiler.compile(new ViewDefinition({
 | |
|           componentId: 'someId',
 | |
|           absUrl: 'someUrl'
 | |
|         })).then( (protoView) => {
 | |
|           expect(DOM.getInnerHTML(resolveInternalDomProtoView(protoView.render).element)).toEqual('url component');
 | |
|           async.done();
 | |
|         });
 | |
|       }));
 | |
| 
 | |
|       it('should report loading errors', inject([AsyncTestCompleter], (async) => {
 | |
|         var compiler = createCompiler(EMPTY_STEP, MapWrapper.create());
 | |
|         PromiseWrapper.catchError(compiler.compile(new ViewDefinition({
 | |
|           componentId: 'someId',
 | |
|           absUrl: 'someUrl'
 | |
|         })), (e) => {
 | |
|           expect(e.message).toContain(`Failed to load the template "someId"`);
 | |
|           async.done();
 | |
|         });
 | |
|       }));
 | |
| 
 | |
|       it('should wait for async subtasks to be resolved', inject([AsyncTestCompleter], (async) => {
 | |
|         var subTasksCompleted = false;
 | |
| 
 | |
|         var completer = PromiseWrapper.completer();
 | |
| 
 | |
|         var compiler = createCompiler( (parent, current, control) => {
 | |
|           ListWrapper.push(mockStepFactory.subTaskPromises, completer.promise.then((_) => {
 | |
|             subTasksCompleted = true;
 | |
|           }));
 | |
|         });
 | |
| 
 | |
|         // It should always return a Promise because the subtask is async
 | |
|         var pvPromise = compiler.compile(new ViewDefinition({
 | |
|           componentId: 'someId',
 | |
|           template: 'some component'
 | |
|         }));
 | |
|         expect(pvPromise).toBePromise();
 | |
|         expect(subTasksCompleted).toEqual(false);
 | |
| 
 | |
|         // The Promise should resolve after the subtask is ready
 | |
|         completer.resolve(null);
 | |
|         pvPromise.then((protoView) => {
 | |
|           expect(subTasksCompleted).toEqual(true);
 | |
|           async.done();
 | |
|         });
 | |
|       }));
 | |
| 
 | |
|       it('should return ProtoViews of type COMPONENT_VIEW_TYPE', inject([AsyncTestCompleter], (async) => {
 | |
|         var compiler = createCompiler(EMPTY_STEP);
 | |
|         compiler.compile(new ViewDefinition({
 | |
|           componentId: 'someId',
 | |
|           template: 'inline component'
 | |
|         })).then( (protoView) => {
 | |
|           expect(protoView.type).toEqual(ProtoViewDto.COMPONENT_VIEW_TYPE);
 | |
|           async.done();
 | |
|         });
 | |
|       }));
 | |
| 
 | |
|     });
 | |
| 
 | |
|     describe('compileHost', () => {
 | |
| 
 | |
|       it('should return ProtoViews of type HOST_VIEW_TYPE', inject([AsyncTestCompleter], (async) => {
 | |
|         var compiler = createCompiler(EMPTY_STEP);
 | |
|         compiler.compileHost(someComponent).then( (protoView) => {
 | |
|           expect(protoView.type).toEqual(ProtoViewDto.HOST_VIEW_TYPE);
 | |
|           async.done();
 | |
|         });
 | |
|       }));
 | |
| 
 | |
|     });
 | |
| 
 | |
|   });
 | |
| 
 | |
| }
 | |
| 
 | |
| class MockStepFactory extends CompileStepFactory {
 | |
|   steps:List<CompileStep>;
 | |
|   subTaskPromises:List<Promise>;
 | |
|   viewDef:ViewDefinition;
 | |
| 
 | |
|   constructor(steps) {
 | |
|     super();
 | |
|     this.steps = steps;
 | |
|   }
 | |
|   createSteps(viewDef, subTaskPromises) {
 | |
|     this.viewDef = viewDef;
 | |
|     this.subTaskPromises = subTaskPromises;
 | |
|     ListWrapper.forEach(this.subTaskPromises, (p) => ListWrapper.push(subTaskPromises, p) );
 | |
|     return this.steps;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 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 EMPTY_STEP = (parent, current, control) => {
 | |
|   if (isPresent(parent)) {
 | |
|     current.inheritedProtoView = parent.inheritedProtoView;
 | |
|   }
 | |
| };
 | |
| 
 | |
| class FakeTemplateLoader extends TemplateLoader {
 | |
|   _urlData: Map<string, string>;
 | |
|   constructor(urlData) {
 | |
|     super(null, new UrlResolver());
 | |
|     this._urlData = urlData;
 | |
|   }
 | |
| 
 | |
|   load(template: ViewDefinition) {
 | |
|     if (isPresent(template.template)) {
 | |
|       return PromiseWrapper.resolve(DOM.createTemplate(template.template));
 | |
|     }
 | |
| 
 | |
|     if (isPresent(template.absUrl)) {
 | |
|       var content = MapWrapper.get(this._urlData, template.absUrl);
 | |
|       if (isPresent(content)) {
 | |
|         return PromiseWrapper.resolve(DOM.createTemplate(content));
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return PromiseWrapper.reject('Load failed');
 | |
|   }
 | |
| }
 | |
| 
 | |
| var someComponent = new DirectiveMetadata({
 | |
|   selector: 'some-comp',
 | |
|   id: 'someComponent',
 | |
|   type: DirectiveMetadata.COMPONENT_TYPE
 | |
| });
 |