angular-cn/modules/angular2/test/render/dom/compiler/compiler_common_tests.ts

339 lines
13 KiB
TypeScript

import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
el,
expect,
iit,
inject,
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, BaseException} 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,
ViewType,
ViewEncapsulation
} from 'angular2/src/render/api';
import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step';
import {CompileStepFactory} from 'angular2/src/render/dom/compiler/compile_step_factory';
import {ElementSchemaRegistry} from 'angular2/src/render/dom/schema/element_schema_registry';
import {ViewLoader, TemplateAndStyles} from 'angular2/src/render/dom/compiler/view_loader';
import {resolveInternalDomProtoView} from 'angular2/src/render/dom/view/proto_view';
import {SharedStylesHost} from 'angular2/src/render/dom/view/shared_styles_host';
import {TemplateCloner} from 'angular2/src/render/dom/template_cloner';
import {MockStep} from './pipeline_spec';
export function runCompilerCommonTests() {
describe('DomCompiler', function() {
var mockStepFactory: MockStepFactory;
var sharedStylesHost: SharedStylesHost;
beforeEach(() => {sharedStylesHost = new SharedStylesHost()});
function createCompiler(processElementClosure = null, processStyleClosure = null,
urlData = null) {
if (isBlank(urlData)) {
urlData = new Map();
}
var tplLoader = new FakeViewLoader(urlData);
mockStepFactory =
new MockStepFactory([new MockStep(processElementClosure, processStyleClosure)]);
return new DomCompiler(new ElementSchemaRegistry(), new TemplateCloner(-1), mockStepFactory,
tplLoader, sharedStylesHost);
}
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 = DirectiveMetadata.create(
{id: 'id', selector: 'custom', type: DirectiveMetadata.COMPONENT_TYPE});
compiler.compileHost(dirMetadata)
.then((protoView) => {
expect(DOM.tagName(DOM.firstChild(DOM.content(templateRoot(protoView))))
.toLowerCase())
.toEqual('custom');
expect(mockStepFactory.viewDef.directives).toEqual([dirMetadata]);
expect(protoView.variableBindings)
.toEqual(MapWrapper.createFromStringMap({'a': 'b'}));
async.done();
});
}));
it('should create element from component selector', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler((parent, current, control) => {
current.inheritedProtoView.bindVariable('b', 'a');
});
var dirMetadata = DirectiveMetadata.create({
id: 'id',
selector: 'marquee.jazzy[size=huge]',
type: DirectiveMetadata.COMPONENT_TYPE
});
compiler.compileHost(dirMetadata)
.then((protoView) => {
let element = DOM.firstChild(DOM.content(templateRoot(protoView)));
expect(DOM.tagName(element).toLowerCase()).toEqual('marquee');
expect(DOM.hasClass(element, 'jazzy')).toBe(true);
expect(DOM.getAttribute(element, 'size')).toEqual('huge');
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(templateRoot(protoView))).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, null, urlData);
compiler.compile(new ViewDefinition({componentId: 'someId', templateAbsUrl: 'someUrl'}))
.then((protoView) => {
expect(DOM.getInnerHTML(templateRoot(protoView))).toEqual('url component');
async.done();
});
}));
it('should remove script tags from templates', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler(EMPTY_STEP);
compiler.compile(new ViewDefinition(
{componentId: 'someId', template: '<div></div><script></script>'}))
.then((protoView) => {
expect(DOM.getInnerHTML(templateRoot(protoView))).toEqual('<div></div>');
async.done();
});
}));
it('should report loading errors', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler(EMPTY_STEP, null, new Map());
PromiseWrapper.catchError(
compiler.compile(
new ViewDefinition({componentId: 'someId', templateAbsUrl: 'someUrl'})),
(e) => {
expect(e.message).toEqual(
'Failed to load the template for "someId" : Failed to fetch url "someUrl"');
async.done();
return null;
});
}));
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(ViewType.COMPONENT);
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(ViewType.HOST);
async.done();
});
}));
});
describe('compile styles', () => {
it('should run the steps', inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler(null, (style) => { return style + 'b {};'; });
compiler.compile(new ViewDefinition(
{componentId: 'someComponent', template: '', styles: ['a {};']}))
.then((protoViewDto) => {
expect(sharedStylesHost.getAllStyles()).toEqual(['a {};b {};']);
async.done();
});
}));
it('should store the styles in the SharedStylesHost for ViewEncapsulation.NONE',
inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler();
compiler.compile(new ViewDefinition({
componentId: 'someComponent',
template: '',
styles: ['a {};'],
encapsulation: ViewEncapsulation.NONE
}))
.then((protoViewDto) => {
expect(DOM.getInnerHTML(templateRoot(protoViewDto))).toEqual('');
expect(sharedStylesHost.getAllStyles()).toEqual(['a {};']);
async.done();
});
}));
it('should store the styles in the SharedStylesHost for ViewEncapsulation.EMULATED',
inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler();
compiler.compile(new ViewDefinition({
componentId: 'someComponent',
template: '',
styles: ['a {};'],
encapsulation: ViewEncapsulation.EMULATED
}))
.then((protoViewDto) => {
expect(DOM.getInnerHTML(templateRoot(protoViewDto))).toEqual('');
expect(sharedStylesHost.getAllStyles()).toEqual(['a {};']);
async.done();
});
}));
if (DOM.supportsNativeShadowDOM()) {
it('should store the styles in the template for ViewEncapsulation.NATIVE',
inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler();
compiler.compile(new ViewDefinition({
componentId: 'someComponent',
template: '',
styles: ['a {};'],
encapsulation: ViewEncapsulation.NATIVE
}))
.then((protoViewDto) => {
expect(DOM.getInnerHTML(templateRoot(protoViewDto)))
.toEqual('<style>a {};</style>');
expect(sharedStylesHost.getAllStyles()).toEqual([]);
async.done();
});
}));
}
it('should default to ViewEncapsulation.NONE if no styles are specified',
inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler();
compiler.compile(
new ViewDefinition({componentId: 'someComponent', template: '', styles: []}))
.then((protoView) => {
expect(mockStepFactory.viewDef.encapsulation).toBe(ViewEncapsulation.NONE);
async.done();
});
}));
it('should default to ViewEncapsulation.EMULATED if styles are specified',
inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler();
compiler.compile(new ViewDefinition(
{componentId: 'someComponent', template: '', styles: ['a {};']}))
.then((protoView) => {
expect(mockStepFactory.viewDef.encapsulation).toBe(ViewEncapsulation.EMULATED);
async.done();
});
}));
});
describe('mergeProtoViews', () => {
it('should store the styles of the merged ProtoView in the SharedStylesHost',
inject([AsyncTestCompleter], (async) => {
var compiler = createCompiler();
compiler.compile(new ViewDefinition(
{componentId: 'someComponent', template: '', styles: ['a {};']}))
.then(protoViewDto => compiler.mergeProtoViewsRecursively([protoViewDto.render]))
.then(_ => {
expect(sharedStylesHost.getAllStyles()).toEqual(['a {};']);
async.done();
});
}));
});
});
}
function templateRoot(protoViewDto: ProtoViewDto): Element {
var pv = resolveInternalDomProtoView(protoViewDto.render);
return (<Element>pv.cloneableTemplate);
}
class MockStepFactory extends CompileStepFactory {
steps: List<CompileStep>;
subTaskPromises: List<Promise<any>>;
viewDef: ViewDefinition;
constructor(steps) {
super();
this.steps = steps;
}
createSteps(viewDef): List<CompileStep> {
this.viewDef = viewDef;
return this.steps;
}
}
var EMPTY_STEP = (parent, current, control) => {
if (isPresent(parent)) {
current.inheritedProtoView = parent.inheritedProtoView;
}
};
class FakeViewLoader extends ViewLoader {
_urlData: Map<string, string>;
constructor(urlData) {
super(null, null, null);
this._urlData = urlData;
}
load(viewDef): Promise<any> {
var styles = isPresent(viewDef.styles) ? viewDef.styles : [];
if (isPresent(viewDef.template)) {
return PromiseWrapper.resolve(new TemplateAndStyles(viewDef.template, styles));
}
if (isPresent(viewDef.templateAbsUrl)) {
var content = this._urlData.get(viewDef.templateAbsUrl);
return isPresent(content) ?
PromiseWrapper.resolve(new TemplateAndStyles(content, styles)) :
PromiseWrapper.reject(`Failed to fetch url "${viewDef.templateAbsUrl}"`, null);
}
throw new BaseException('View should have either the templateUrl or template property set');
}
}
var someComponent = DirectiveMetadata.create(
{selector: 'some-comp', id: 'someComponent', type: DirectiveMetadata.COMPONENT_TYPE});