refactor(template loading): add support for base URLs, css rewriting

fixes #654
This commit is contained in:
Victor Berchet
2015-02-24 16:05:45 +01:00
parent 26872f60e6
commit 929fc65493
42 changed files with 1147 additions and 634 deletions

View File

@ -15,6 +15,9 @@ import {CompileStep} from 'angular2/src/core/compiler/pipeline/compile_step'
import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_control';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {ComponentUrlMapper, RuntimeComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {Lexer, Parser, dynamicChangeDetection} from 'angular2/change_detection';
import {ShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
@ -41,7 +44,10 @@ export function main() {
function createCompiler(processClosure) {
var steps = [new MockStep(processClosure)];
return new TestableCompiler(reader, steps, new FakeTemplateLoader(), tplResolver);
var urlResolver = new FakeUrlResolver();
var tplLoader = new FakeTemplateLoader(urlResolver);
return new TestableCompiler(reader, steps,tplLoader, tplResolver,
urlResolver, new ComponentUrlMapper());
}
it('should run the steps and return the ProtoView of the root element', (done) => {
@ -66,6 +72,32 @@ export function main() {
});
});
it('should wait for async styles to be resolved', (done) => {
var styleResolved = false;
var completer = PromiseWrapper.completer();
var compiler = createCompiler( (parent, current, control) => {
var protoView = new ProtoView(current.element, null, null);
ListWrapper.push(protoView.stylePromises, completer.promise.then((_) => {
styleResolved = true;
}));
current.inheritedProtoView = protoView;
});
// It should always return a Promise because the style is async
var pvPromise = compiler.compile(MainComponent);
expect(pvPromise).toBePromise();
expect(styleResolved).toEqual(false);
// The Promise should resolve after the style is ready
completer.resolve(null);
pvPromise.then((protoView) => {
expect(styleResolved).toEqual(true);
done();
});
});
it('should load nested components', (done) => {
var compiler = createCompiler( (parent, current, control) => {
if (DOM.hasClass(current.element, 'nested')) {
@ -102,8 +134,8 @@ export function main() {
it('should re-use components being compiled', (done) => {
var nestedElBinders = [];
var compiler = createCompiler( (parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null);
if (DOM.hasClass(current.element, 'nested')) {
current.inheritedProtoView = new ProtoView(current.element, null, null);
current.inheritedElementBinder = current.inheritedProtoView.bindElement(null);
current.componentDirective = reader.read(NestedComponent);
ListWrapper.push(nestedElBinders, current.inheritedElementBinder);
@ -134,9 +166,12 @@ export function main() {
describe('(mixed async, sync TemplateLoader)', () => {
var reader = new DirectiveMetadataReader();
function createCompiler(processClosure, resolver: TemplateResolver) {
function createCompiler(processClosure, templateResolver: TemplateResolver) {
var steps = [new MockStep(processClosure)];
return new TestableCompiler(reader, steps, new FakeTemplateLoader(), resolver);
var urlResolver = new FakeUrlResolver();
var tplLoader = new FakeTemplateLoader(urlResolver);
return new TestableCompiler(reader, steps, tplLoader, templateResolver,
urlResolver, new ComponentUrlMapper());
}
function createNestedComponentSpec(name, resolver: TemplateResolver, error:string = null) {
@ -167,47 +202,72 @@ export function main() {
});
}
var resolver = new FakeTemplateResolver();
resolver.setSync(ParentComponent);
resolver.setSync(NestedComponent);
createNestedComponentSpec('(sync -> sync)', resolver);
var templateResolver = new FakeTemplateResolver();
templateResolver.setSync(ParentComponent);
templateResolver.setSync(NestedComponent);
createNestedComponentSpec('(sync -> sync)', templateResolver);
resolver = new FakeTemplateResolver();
resolver.setAsync(ParentComponent);
resolver.setSync(NestedComponent);
createNestedComponentSpec('(async -> sync)', resolver);
templateResolver = new FakeTemplateResolver();
templateResolver.setAsync(ParentComponent);
templateResolver.setSync(NestedComponent);
createNestedComponentSpec('(async -> sync)', templateResolver);
resolver = new FakeTemplateResolver();
resolver.setSync(ParentComponent);
resolver.setAsync(NestedComponent);
createNestedComponentSpec('(sync -> async)', resolver);
templateResolver = new FakeTemplateResolver();
templateResolver.setSync(ParentComponent);
templateResolver.setAsync(NestedComponent);
createNestedComponentSpec('(sync -> async)', templateResolver);
resolver = new FakeTemplateResolver();
resolver.setAsync(ParentComponent);
resolver.setAsync(NestedComponent);
createNestedComponentSpec('(async -> async)', resolver);
templateResolver = new FakeTemplateResolver();
templateResolver.setAsync(ParentComponent);
templateResolver.setAsync(NestedComponent);
createNestedComponentSpec('(async -> async)', templateResolver);
resolver = new FakeTemplateResolver();
resolver.setError(ParentComponent);
resolver.setSync(NestedComponent);
createNestedComponentSpec('(error -> sync)', resolver,
templateResolver = new FakeTemplateResolver();
templateResolver.setError(ParentComponent);
templateResolver.setSync(NestedComponent);
createNestedComponentSpec('(error -> sync)', templateResolver,
'Failed to load the template for ParentComponent');
// TODO(vicb): Check why errors this fails with Dart
// TODO(vicb): The Promise is rejected with the correct error but an exc is thrown before
//resolver = new FakeTemplateResolver();
//resolver.setSync(ParentComponent);
//resolver.setError(NestedComponent);
//createNestedComponentSpec('(sync -> error)', resolver,
//templateResolver = new FakeTemplateResolver();
//templateResolver.setSync(ParentComponent);
//templateResolver.setError(NestedComponent);
//createNestedComponentSpec('(sync -> error)', templateResolver,
// 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent');
//
//resolver = new FakeTemplateResolver();
//resolver.setAsync(ParentComponent);
//resolver.setError(NestedComponent);
//createNestedComponentSpec('(async -> error)', resolver,
//templateResolver = new FakeTemplateResolver();
//templateResolver.setAsync(ParentComponent);
//templateResolver.setError(NestedComponent);
//createNestedComponentSpec('(async -> error)', templateResolver,
// 'Failed to load the template for NestedComponent -> Failed to compile ParentComponent');
});
describe('URL resolution', () => {
it('should resolve template URLs by combining application, component and template URLs', (done) => {
var steps = [new MockStep((parent, current, control) => {
current.inheritedProtoView = new ProtoView(current.element, null, null);
})];
var reader = new DirectiveMetadataReader();
var tplResolver = new FakeTemplateResolver();
var urlResolver = new FakeUrlResolver();
var tplLoader = new FakeTemplateLoader(urlResolver);
var template = new Template({inline: '<div></div>', url: '/tpl.html'});
var cmpUrlMapper = new RuntimeComponentUrlMapper();
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp');
var compiler = new TestableCompiler(reader, steps, tplLoader, tplResolver,
urlResolver, cmpUrlMapper);
tplResolver.forceSync();
tplResolver.setTemplate(MainComponent, template);
compiler.compile(MainComponent).then((protoView) => {
expect(tplLoader.getTemplateUrl(template)).toEqual('http://www.app.com/cmp/tpl.html');
done();
});
})
});
});
}
@ -231,9 +291,17 @@ class TestableCompiler extends Compiler {
steps:List;
constructor(reader:DirectiveMetadataReader, steps:List<CompileStep>, loader: TemplateLoader,
resolver: TemplateResolver) {
super(dynamicChangeDetection, loader, reader, new Parser(new Lexer()), new CompilerCache(),
new NativeShadowDomStrategy(), resolver);
templateResolver: TemplateResolver, urlResolver: UrlResolver, cmpUrlMapper: ComponentUrlMapper) {
super(dynamicChangeDetection,
loader,
reader,
new Parser(new Lexer()),
new CompilerCache(),
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
templateResolver,
cmpUrlMapper,
urlResolver);
this.steps = steps;
}
@ -253,9 +321,23 @@ class MockStep extends CompileStep {
}
}
class FakeTemplateLoader extends TemplateLoader {
class FakeUrlResolver extends UrlResolver {
constructor() {
super(null);
super();
}
resolve(baseUrl: string, url: string): string {
if (baseUrl === null && url == './') {
return 'http://www.app.com';
};
return baseUrl + url;
}
}
class FakeTemplateLoader extends TemplateLoader {
constructor(urlResolver: UrlResolver) {
super(null, urlResolver);
}
load(template: Template) {
@ -307,14 +389,14 @@ class FakeTemplateResolver extends TemplateResolver {
}
if (ListWrapper.contains(this._syncCmp, component)) {
return new Template({inline: html});
return template;
}
if (ListWrapper.contains(this._asyncCmp, component)) {
return new Template({url: html});
}
if (this._forceSync) return new Template({inline: html});
if (this._forceSync) return template;
if (this._forceAsync) return new Template({url: html});
throw 'No template';

View File

@ -0,0 +1,25 @@
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
import {
ComponentUrlMapper,
RuntimeComponentUrlMapper
} from 'angular2/src/core/compiler/component_url_mapper';
export function main() {
describe('RuntimeComponentUrlMapper', () => {
it('should return the registered URL', () => {
var url = 'http://path/to/component';
var mapper = new RuntimeComponentUrlMapper();
mapper.setComponentUrl(SomeComponent, url);
expect(mapper.getUrl(SomeComponent)).toEqual(url);
});
it('should fallback to ComponentUrlMapper', () => {
var mapper = new ComponentUrlMapper();
var runtimeMapper = new RuntimeComponentUrlMapper();
expect(runtimeMapper.getUrl(SomeComponent)).toEqual(mapper.getUrl(SomeComponent));
});
});
}
class SomeComponent {}

View File

@ -14,6 +14,9 @@ import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_str
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
import {Template} from 'angular2/src/core/annotations/template';
@ -28,13 +31,16 @@ export function main() {
var compiler, tplResolver;
function createCompiler(tplResolver, changedDetection) {
var urlResolver = new UrlResolver();
return new Compiler(changedDetection,
new TemplateLoader(null),
new TemplateLoader(null, null),
new DirectiveMetadataReader(),
new Parser(new Lexer()),
new CompilerCache(),
new NativeShadowDomStrategy(),
tplResolver
new NativeShadowDomStrategy(new StyleUrlResolver(urlResolver)),
tplResolver,
new ComponentUrlMapper(),
urlResolver
);
}

View File

@ -72,7 +72,7 @@ export function main() {
current.inheritedProtoView = new ProtoView(
current.element,
new DynamicProtoChangeDetector(normalizeBlank(registry)),
new NativeShadowDomStrategy());
new NativeShadowDomStrategy(null));
} else if (isPresent(parent)) {
current.inheritedProtoView = parent.inheritedProtoView;
}
@ -380,7 +380,7 @@ export function main() {
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(null), new NativeShadowDomStrategy());
el('<div></div>'), new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
instantiateView(pv);
evalContext.prop1 = 'a';
@ -416,7 +416,7 @@ export function main() {
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(registry), new NativeShadowDomStrategy());
el('<div></div>'), new DynamicProtoChangeDetector(registry), new NativeShadowDomStrategy(null));
instantiateView(pv);
evalContext.prop1 = 'a';

View File

@ -21,7 +21,7 @@ export function main() {
current.variableBindings = MapWrapper.createFromStringMap(variableBindings);
}
current.inheritedElementBinder = new ElementBinder(null, null, null);
}), new ProtoViewBuilder(dynamicChangeDetection, new NativeShadowDomStrategy())]);
}), new ProtoViewBuilder(dynamicChangeDetection, new NativeShadowDomStrategy(null))]);
}
it('should not create a ProtoView when the isViewRoot flag is not set', () => {

View File

@ -0,0 +1,137 @@
import {
describe,
beforeEach,
expect,
it,
iit,
ddescribe,
el,
SpyObject,
proxy,
} from 'angular2/test_lib';
import {CompilePipeline} from 'angular2/src/core/compiler/pipeline/compile_pipeline';
import {ResolveCss} from 'angular2/src/core/compiler/pipeline/resolve_css';
import {CompileElement} from 'angular2/src/core/compiler/pipeline/compile_element';
import {CompileStep} from 'angular2/src/core/compiler/pipeline/compile_step';
import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_control';
import {Component} from 'angular2/src/core/annotations/annotations';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {ProtoView} from 'angular2/src/core/compiler/view';
import {IMPLEMENTS, Type, stringify} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/facade/dom';
import {PromiseWrapper} from 'angular2/src/facade/async';
export function main() {
describe('ResolveCss', () => {
function createPipeline(strategy:ShadowDomStrategy) {
var annotation = new Component({selector: 'selector'});
var meta = new DirectiveMetadata(SomeComponent, annotation);
var resolveCss = new ResolveCss(meta, strategy, 'http://base');
return new CompilePipeline([
new MockStep((parent, current, control) => {
current.inheritedProtoView = new ProtoView(null, null, null);
}),
resolveCss
]);
}
it('it should set ignoreBindings to true for style elements', () => {
var strategy = new DummyStrategy();
strategy.spy('transformStyleText').andCallFake((a, b, c) => '.css {}');
strategy.spy('handleStyleElement');
var pipeline = createPipeline(strategy);
var results = pipeline.process(el('<div><style></style></div>'));
expect(results[0].ignoreBindings).toBe(false);
expect(results[1].ignoreBindings).toBe(true);
});
it('should delegate the handling of style elements to the strategy', () => {
var strategy = new DummyStrategy();
strategy.spy('transformStyleText').andCallFake((a, b, c) => '.css {}');
strategy.spy('handleStyleElement');
var pipeline = createPipeline(strategy);
var template = el('<div></div>');
var styleEl = el('<style></style>');
DOM.appendChild(template, styleEl);
pipeline.process(template);
expect(strategy.spy('handleStyleElement')).toHaveBeenCalledWith(styleEl);
});
it('should handle css transformed synchronously', () => {
var strategy = new DummyStrategy();
strategy.spy('transformStyleText').andCallFake((css, url, cmp) => {
return `${css}, ${url}, ${stringify(cmp)}`;
});
strategy.spy('handleStyleElement');
var pipeline = createPipeline(strategy);
var template = el('<div></div>');
var styleEl = el('<style>/*css*/</style>');
DOM.appendChild(template, styleEl);
var results = pipeline.process(template);
expect(styleEl).toHaveText('/*css*/, http://base, SomeComponent');
expect(results[0].inheritedProtoView.stylePromises.length).toBe(0);
});
it('should handle css transformed asynchronously', (done) => {
var completer = PromiseWrapper.completer();
var strategy = new DummyStrategy();
var futureCss;
strategy.spy('transformStyleText').andCallFake((css, url, cmp) => {
futureCss = `${css}, ${url}, ${stringify(cmp)}`;
return completer.promise;
});
strategy.spy('handleStyleElement');
var pipeline = createPipeline(strategy);
var template = el('<div></div>');
var styleEl = el('<style>/*css*/</style>');
DOM.appendChild(template, styleEl);
var results = pipeline.process(template);
// The css should be empty before the style promise is resolved
expect(styleEl).toHaveText('');
expect(results[0].inheritedProtoView.stylePromises[0]).toBe(completer.promise);
completer.resolve(futureCss);
// TODO(vicb): refactor once we have better support for async tests
completer.promise.then((_) => {
expect(styleEl).toHaveText('/*css*/, http://base, SomeComponent');
done();
});
});
});
}
@proxy
@IMPLEMENTS(ShadowDomStrategy)
class DummyStrategy extends SpyObject {
noSuchMethod(m) {
return super.noSuchMethod(m)
}
}
class SomeComponent {}
class MockStep extends CompileStep {
processClosure:Function;
constructor(process) {
super();
this.processClosure = process;
}
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
this.processClosure(parent, current, control);
}
}

View File

@ -1,102 +0,0 @@
import {describe, beforeEach, expect, it, iit, ddescribe, el} from 'angular2/test_lib';
import {CompilePipeline} from 'angular2/src/core/compiler/pipeline/compile_pipeline';
import {ShimShadowCss} from 'angular2/src/core/compiler/pipeline/shim_shadow_css';
import {ShimComponent} from 'angular2/src/core/compiler/shadow_dom_emulation/shim_component';
import {Component} from 'angular2/src/core/annotations/annotations';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {Type} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/facade/dom';
export function main() {
describe('ShimShadowCss', () => {
function createPipeline(strategy:ShadowDomStrategy, styleHost) {
var component = new Component({selector: 'selector'});
var meta = new DirectiveMetadata(null, component);
var shimShadowCss = new ShimShadowCss(meta, strategy, styleHost);
return new CompilePipeline([shimShadowCss]);
}
it('it should set ignoreBindings to true for style elements', () => {
var host = el('<div></div>');
var pipeline = createPipeline(new FakeStrategy(false), host);
var results = pipeline.process(el('<div><style></style></div>'));
expect(results[0].ignoreBindings).toBe(false);
expect(results[1].ignoreBindings).toBe(true);
});
it('should not extract the styles when extractStyles() is false', () => {
var host = el('<div></div>');
var pipeline = createPipeline(new FakeStrategy(false), host);
var template = el('<style>.s{}</style>');
pipeline.process(template);
expect(template).toHaveText('.s{}');
});
it('should move the styles to the host when extractStyles() is true', () => {
var host = el('<div></div>');
var pipeline = createPipeline(new FakeStrategy(true), host);
var template = el('<div><style>.s{}</style></div>');
pipeline.process(template);
expect(template).toHaveText('');
expect(host).toHaveText('/* shim */.s{}');
});
it('should preserve original content when moving styles', () => {
var host = el('<div>original content</div>');
var pipeline = createPipeline(new FakeStrategy(true), host);
var template = el('<div><style>.s{}</style></div>');
pipeline.process(template);
expect(template).toHaveText('');
expect(host).toHaveText('/* shim */.s{}original content');
});
it('should preserve attributes on moved style', () => {
var host = el('<div></div>');
var pipeline = createPipeline(new FakeStrategy(true), host);
var template = el('<div><style media="print">.s{}</style></div>');
pipeline.process(template);
var styleEl = DOM.firstChild(host);
expect(DOM.getAttribute(styleEl, 'media')).toEqual('print');
});
it('should move the styles to the host in the original order', () => {
var host = el('<div></div>');
var pipeline = createPipeline(new FakeStrategy(true), host);
var template = el('<div><style>.s1{}</style><style>.s2{}</style></div>');
pipeline.process(template);
expect(host).toHaveText('/* shim */.s1{}/* shim */.s2{}');
});
});
}
class FakeStrategy extends ShadowDomStrategy {
_extractStyles: boolean;
constructor(extractStyles: boolean) {
super();
this._extractStyles = extractStyles;
}
extractStyles(): boolean {
return this._extractStyles;
}
getShimComponent(component: Type): ShimComponent {
return new FakeShimComponent(component);
}
}
class FakeShimComponent extends ShimComponent {
constructor(component: Type) {
super(component);
}
shimCssText(cssText: string): string {
return '/* shim */' + cssText;
}
}

View File

@ -5,20 +5,19 @@ import {ShimShadowDom} from 'angular2/src/core/compiler/pipeline/shim_shadow_dom
import {CompileElement} from 'angular2/src/core/compiler/pipeline/compile_element';
import {CompileStep} from 'angular2/src/core/compiler/pipeline/compile_step';
import {CompileControl} from 'angular2/src/core/compiler/pipeline/compile_control';
import {ShimComponent} from 'angular2/src/core/compiler/shadow_dom_emulation/shim_component';
import {Component} from 'angular2/src/core/annotations/annotations';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {Type, isBlank} from 'angular2/src/facade/lang';
import {Type, isBlank, stringify} from 'angular2/src/facade/lang';
import {DOM, Element} from 'angular2/src/facade/dom';
export function main() {
describe('ShimShadowDom', () => {
function createPipeline(ignoreBindings: boolean) {
var component = new Component({selector: 'selector'});
var meta = new DirectiveMetadata(null, component);
var annotation = new Component({selector: 'selector'});
var meta = new DirectiveMetadata(SomeComponent, annotation);
var shimShadowDom = new ShimShadowDom(meta, new FakeStrategy());
return new CompilePipeline([
@ -38,22 +37,22 @@ export function main() {
it('should add the content attribute to content element', () => {
var pipeline = createPipeline(false);
var results = pipeline.process(el('<div></div>'));
expect(DOM.getAttribute(results[0].element, '_ngcontent')).toEqual('content');
expect(isBlank(DOM.getAttribute(results[0].element, '_nghost'))).toBeTruthy();
expect(DOM.getAttribute(results[0].element, 'SomeComponent-content')).toEqual('');
expect(isBlank(DOM.getAttribute(results[0].element, 'SomeComponent-host'))).toBeTruthy();
});
it('should add both the content and host attributes to host element', () => {
var pipeline = createPipeline(false);
var results = pipeline.process(el('<div class="host"></div>'));
expect(DOM.getAttribute(results[0].element, '_ngcontent')).toEqual('content');
expect(DOM.getAttribute(results[0].element, '_nghost')).toEqual('host');
expect(DOM.getAttribute(results[0].element, 'SomeComponent-content')).toEqual('');
expect(DOM.getAttribute(results[0].element, 'SomeComponent-host')).toEqual('');
});
it('should do nothing when ignoreBindings is true', () => {
var pipeline = createPipeline(true);
var results = pipeline.process(el('<div class="host"></div>'));
expect(isBlank(DOM.getAttribute(results[0].element, '_ngcontent'))).toBeTruthy();
expect(isBlank(DOM.getAttribute(results[0].element, '_nghost'))).toBeTruthy();
expect(isBlank(DOM.getAttribute(results[0].element, 'SomeComponent-content'))).toBeTruthy();
expect(isBlank(DOM.getAttribute(results[0].element, 'SomeComponent-host'))).toBeTruthy();
});
});
}
@ -63,22 +62,14 @@ class FakeStrategy extends ShadowDomStrategy {
super();
}
getShimComponent(component: Type): ShimComponent {
return new FakeShimComponent(component);
}
}
class FakeShimComponent extends ShimComponent {
constructor(component: Type) {
super(component);
shimContentElement(component: Type, element: Element) {
var attrName = stringify(component) + '-content';
DOM.setAttribute(element, attrName, '');
}
shimContentElement(element: Element) {
DOM.setAttribute(element, '_ngcontent', 'content');
}
shimHostElement(element: Element) {
DOM.setAttribute(element, '_nghost', 'host');
shimHostElement(component: Type, element: Element) {
var attrName = stringify(component) + '-host';
DOM.setAttribute(element, attrName, '');
}
}

View File

@ -2,6 +2,7 @@ import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular
import {StringMapWrapper, List} from 'angular2/src/facade/collection';
import {Type} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/facade/dom';
import {Injector} from 'angular2/di';
import {Lexer, Parser, ChangeDetector, dynamicChangeDetection} from 'angular2/change_detection';
@ -14,6 +15,11 @@ import {ShadowDomStrategy,
NativeShadowDomStrategy,
EmulatedShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {StyleInliner} from 'angular2/src/core/compiler/style_inliner';
import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock';
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations/annotations';
@ -23,10 +29,13 @@ import {ViewContainer} from 'angular2/src/core/compiler/view_container';
export function main() {
describe('integration tests', function() {
var urlResolver = new UrlResolver();
var styleUrlResolver = new StyleUrlResolver(urlResolver);
var styleInliner = new StyleInliner(null, styleUrlResolver, urlResolver);
StringMapWrapper.forEach({
"native" : new NativeShadowDomStrategy(),
"emulated" : new EmulatedShadowDomStrategy()
"native" : new NativeShadowDomStrategy(styleUrlResolver),
"emulated" : new EmulatedShadowDomStrategy(styleInliner, styleUrlResolver, DOM.createElement('div'))
},
(strategy, name) => {
@ -36,12 +45,14 @@ export function main() {
beforeEach(() => {
tplResolver = new MockTemplateResolver();
compiler = new Compiler(dynamicChangeDetection,
new TemplateLoader(null),
new TemplateLoader(null, null),
new DirectiveMetadataReader(),
new Parser(new Lexer()),
new CompilerCache(),
strategy,
tplResolver
tplResolver,
new ComponentUrlMapper(),
urlResolver
);
});

View File

@ -1,128 +0,0 @@
import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el} from 'angular2/test_lib';
import {
ShimNativeComponent,
ShimEmulatedComponent,
resetShimComponentCache
} from 'angular2/src/core/compiler/shadow_dom_emulation/shim_component';
import {ShadowCss} from 'angular2/src/core/compiler/shadow_dom_emulation/shadow_css';
import {Type} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/facade/dom';
export function main() {
describe('ShimComponent', () => {
describe('ShimNativeComponent', () => {
function createShim(component: Type) {
return new ShimNativeComponent(component);
}
it('should not transform the CSS', () => {
var css = '.foo {color: blue;} :host{color: red;}';
var shim = createShim(SomeComponent);
var shimCss = shim.shimCssText(css);
expect(css).toEqual(shimCss);
});
it('should not transform content elements', () => {
var html = '<p>foo</p>';
var element = el(html);
var shim = createShim(SomeComponent);
shim.shimContentElement(element);
expect(DOM.getOuterHTML(element)).toEqual(html);
});
it('should not transform host elements', () => {
var html = '<p>foo</p>';
var element = el(html);
var shim = createShim(SomeComponent);
shim.shimHostElement(element);
expect(DOM.getOuterHTML(element)).toEqual(html);
});
});
describe('ShimEmulatedComponent', () => {
beforeEach(() => {
resetShimComponentCache();
});
function createShim(component: Type) {
return new ShimEmulatedComponent(component);
}
it('should transform the CSS', () => {
var css = '.foo {color: blue;} :host{color: red;}';
var shim = createShim(SomeComponent);
var shimCss = shim.shimCssText(css);
expect(shimCss).not.toEqual(css);
var shadowCss = new ShadowCss();
expect(shimCss).toEqual(shadowCss.shimCssText(css, '_ngcontent-0', '_nghost-0'));
});
it('should transform content elements', () => {
var html = '<p>foo</p>';
var element = el(html);
var shim = createShim(SomeComponent);
shim.shimContentElement(element);
expect(DOM.getOuterHTML(element)).toEqual('<p _ngcontent-0="">foo</p>');
});
it('should not transform host elements', () => {
var html = '<p>foo</p>';
var element = el(html);
var shim = createShim(SomeComponent);
shim.shimHostElement(element);
expect(DOM.getOuterHTML(element)).toEqual('<p _nghost-0="">foo</p>');
});
it('should generate the same output for the same component', () => {
var html = '<p>foo</p>';
var content1 = el(html);
var host1 = el(html);
var css = '.foo {color: blue;} :host{color: red;}';
var shim1 = createShim(SomeComponent);
shim1.shimContentElement(content1);
shim1.shimHostElement(host1);
var shimCss1 = shim1.shimCssText(css);
var content2 = el(html);
var host2 = el(html);
var shim2 = createShim(SomeComponent);
shim2.shimContentElement(content2);
shim2.shimHostElement(host2);
var shimCss2 = shim2.shimCssText(css);
expect(DOM.getOuterHTML(content1)).toEqual(DOM.getOuterHTML(content2));
expect(DOM.getOuterHTML(host1)).toEqual(DOM.getOuterHTML(host2));
expect(shimCss1).toEqual(shimCss2);
});
it('should generate different outputs for different components', () => {
var html = '<p>foo</p>';
var content1 = el(html);
var host1 = el(html);
var css = '.foo {color: blue;} :host{color: red;}';
var shim1 = createShim(SomeComponent);
shim1.shimContentElement(content1);
shim1.shimHostElement(host1);
var shimCss1 = shim1.shimCssText(css);
var content2 = el(html);
var host2 = el(html);
var shim2 = createShim(SomeComponent2);
shim2.shimContentElement(content2);
shim2.shimHostElement(host2);
var shimCss2 = shim2.shimCssText(css);
expect(DOM.getOuterHTML(content1)).not.toEqual(DOM.getOuterHTML(content2));
expect(DOM.getOuterHTML(host1)).not.toEqual(DOM.getOuterHTML(host2));
expect(shimCss1).not.toEqual(shimCss2);
});
});
});
}
class SomeComponent {}
class SomeComponent2 {}

View File

@ -0,0 +1,169 @@
import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el} from 'angular2/test_lib';
import {
NativeShadowDomStrategy,
EmulatedShadowDomStrategy,
resetShadowDomCache,
} from 'angular2/src/core/compiler/shadow_dom_strategy';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
import {StyleInliner} from 'angular2/src/core/compiler/style_inliner';
import {ProtoView} from 'angular2/src/core/compiler/view';
import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/facade/dom';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
import {DynamicProtoChangeDetector} from 'angular2/change_detection';
export function main() {
var strategy;
describe('NativeShadowDomStratgey', () => {
beforeEach(() => {
var urlResolver = new UrlResolver();
var styleUrlResolver = new StyleUrlResolver(urlResolver);
strategy = new NativeShadowDomStrategy(styleUrlResolver);
});
it('should attach the view nodes to the shadow root', () => {
var host = el('<div></div>');
var nodes = el('<div>view</div>');
var pv = new ProtoView(nodes, new DynamicProtoChangeDetector(null), null);
var view = pv.instantiate(null, null);
strategy.attachTemplate(host, view);
var shadowRoot = DOM.getShadowRoot(host);
expect(isPresent(shadowRoot)).toBeTruthy();
expect(shadowRoot).toHaveText('view');
});
it('should rewrite style urls', () => {
var css = '.foo {background-image: url("img.jpg");}';
expect(strategy.transformStyleText(css, 'http://base', null))
.toEqual(".foo {background-image: url('http://base/img.jpg');}");
});
it('should not inline import rules', () => {
var css = '@import "other.css";';
expect(strategy.transformStyleText(css, 'http://base', null))
.toEqual("@import 'http://base/other.css';");
});
});
describe('EmulatedShadowDomStratgey', () => {
var xhr, styleHost;
beforeEach(() => {
var urlResolver = new UrlResolver();
var styleUrlResolver = new StyleUrlResolver(urlResolver);
xhr = new FakeXHR();
var styleInliner = new StyleInliner(xhr, styleUrlResolver, urlResolver);
styleHost = el('<div></div>');
strategy = new EmulatedShadowDomStrategy(styleInliner, styleUrlResolver, styleHost);
resetShadowDomCache();
});
it('should attach the view nodes as child of the host element', () => {
var host = el('<div><span>original content</span></div>');
var nodes = el('<div>view</div>');
var pv = new ProtoView(nodes, new DynamicProtoChangeDetector(null), null);
var view = pv.instantiate(null, null);
strategy.attachTemplate(host, view);
var firstChild = DOM.firstChild(host);
expect(DOM.tagName(firstChild)).toEqual('DIV');
expect(firstChild).toHaveText('view');
expect(host).toHaveText('view');
});
it('should rewrite style urls', () => {
var css = '.foo {background-image: url("img.jpg");}';
expect(strategy.transformStyleText(css, 'http://base', SomeComponent))
.toEqual(".foo[_ngcontent-0] {\nbackground-image: url(http://base/img.jpg);\n}");
});
it('should scope style', () => {
var css = '.foo {} :host {}';
expect(strategy.transformStyleText(css, 'http://base', SomeComponent))
.toEqual(".foo[_ngcontent-0] {\n\n}\n\n[_nghost-0] {\n\n}");
});
it('should inline @import rules', (done) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import "one.css";';
var promise = strategy.transformStyleText(css, 'http://base', SomeComponent);
expect(promise).toBePromise();
promise.then((css) => {
expect(css).toEqual('.one[_ngcontent-0] {\n\n}');
done();
});
});
it('should return the same style given the same component', () => {
var css = '.foo {} :host {}';
expect(strategy.transformStyleText(css, 'http://base', SomeComponent))
.toEqual(".foo[_ngcontent-0] {\n\n}\n\n[_nghost-0] {\n\n}");
expect(strategy.transformStyleText(css, 'http://base', SomeComponent))
.toEqual(".foo[_ngcontent-0] {\n\n}\n\n[_nghost-0] {\n\n}");
});
it('should return different styles given different components', () => {
var css = '.foo {} :host {}';
expect(strategy.transformStyleText(css, 'http://base', SomeComponent))
.toEqual(".foo[_ngcontent-0] {\n\n}\n\n[_nghost-0] {\n\n}");
expect(strategy.transformStyleText(css, 'http://base', SomeOtherComponent))
.toEqual(".foo[_ngcontent-1] {\n\n}\n\n[_nghost-1] {\n\n}");
});
it('should move the style element to the style host', () => {
var originalHost = el('<div></div>');
var styleEl = el('<style>/*css*/</style>');
DOM.appendChild(originalHost, styleEl);
expect(originalHost).toHaveText('/*css*/');
strategy.handleStyleElement(styleEl);
expect(originalHost).toHaveText('');
expect(styleHost).toHaveText('/*css*/');
});
it('should add an attribute to the content elements', () => {
var elt = el('<div></div>');
strategy.shimContentElement(SomeComponent, elt);
expect(DOM.getAttribute(elt, '_ngcontent-0')).toEqual('');
});
it('should add an attribute to the host elements', () => {
var elt = el('<div></div>');
strategy.shimHostElement(SomeComponent, elt);
expect(DOM.getAttribute(elt, '_nghost-0')).toEqual('');
});
});
}
class FakeXHR extends XHR {
_responses: Map;
constructor() {
super();
this._responses = MapWrapper.create();
}
get(url: string): Promise<string> {
var response = MapWrapper.get(this._responses, url);
if (isBlank(response)) {
return PromiseWrapper.reject('xhr error');
}
return PromiseWrapper.resolve(response);
}
reply(url: string, response: string) {
MapWrapper.set(this._responses, url, response);
}
}
class SomeComponent {}
class SomeOtherComponent {}

View File

@ -6,24 +6,50 @@ import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {XHR} from 'angular2/src/core/compiler/xhr/xhr';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver';
export function main() {
describe('StyleInliner', () => {
var xhr, inliner;
beforeEach(() => {
xhr = new FakeXHR();
var urlResolver = new UrlResolver();
var styleUrlResolver = new StyleUrlResolver(urlResolver);
inliner = new StyleInliner(xhr, styleUrlResolver, urlResolver);
});
describe('loading', () => {
it('should return a string when there is no import statement', () => {
var css = '.main {}';
var loader = new StyleInliner(null);
var loadedCss = loader.inlineImports(css);
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).not.toBePromise();
expect(loadedCss).toEqual(css);
});
it('should inline @import rules', (done) => {
var xhr = new FakeXHR();
xhr.reply('one.css', '.one {}');
var css = '@import "one.css";.main {}';
var loader = new StyleInliner(xhr);
var loadedCss = loader.inlineImports(css);
xhr.reply('http://base/one.css', '.one {}');
var css = '@import url("one.css");.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.main {}');
done();
},
function(e) {
throw 'fail;'
}
);
});
// TODO(vicb): fix the StyleInliner
xit('should support url([unquoted url]) in @import rules', (done) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import url(one.css);.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
@ -38,15 +64,13 @@ export function main() {
});
it('should handle @import error gracefuly', (done) => {
var xhr = new FakeXHR();
var css = '@import "one.css";.main {}';
var loader = new StyleInliner(xhr);
var loadedCss = loader.inlineImports(css);
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('/* failed to import one.css */\n.main {}');
expect(css).toEqual('/* failed to import http://base/one.css */\n.main {}');
done();
},
function(e) {
@ -56,12 +80,10 @@ export function main() {
});
it('should inline multiple @import rules', (done) => {
var xhr = new FakeXHR();
xhr.reply('one.css', '.one {}');
xhr.reply('two.css', '.two {}');
xhr.reply('http://base/one.css', '.one {}');
xhr.reply('http://base/two.css', '.two {}');
var css = '@import "one.css";@import "two.css";.main {}';
var loader = new StyleInliner(xhr);
var loadedCss = loader.inlineImports(css);
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
@ -76,12 +98,10 @@ export function main() {
});
it('should inline nested @import rules', (done) => {
var xhr = new FakeXHR();
xhr.reply('one.css', '@import "two.css";.one {}');
xhr.reply('two.css', '.two {}');
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
xhr.reply('http://base/two.css', '.two {}');
var css = '@import "one.css";.main {}';
var loader = new StyleInliner(xhr);
var loadedCss = loader.inlineImports(css);
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
@ -96,12 +116,10 @@ export function main() {
});
it('should handle circular dependencies gracefuly', (done) => {
var xhr = new FakeXHR();
xhr.reply('one.css', '@import "two.css";.one {}');
xhr.reply('two.css', '@import "one.css";.two {}');
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
xhr.reply('http://base/two.css', '@import "one.css";.two {}');
var css = '@import "one.css";.main {}';
var loader = new StyleInliner(xhr);
var loadedCss = loader.inlineImports(css);
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
@ -115,15 +133,29 @@ export function main() {
);
});
it('should handle invalid @import fracefuly', (done) => {
// Invalid rule: the url is not quoted
var css = '@import one.css;.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('/* Invalid import rule: "@import one.css;" */.main {}');
done();
},
function(e) {
throw 'fail;'
}
);
});
});
describe('media query', () => {
it('should wrap inlined content in media query', (done) => {
var xhr = new FakeXHR();
xhr.reply('one.css', '.one {}');
xhr.reply('http://base/one.css', '.one {}');
var css = '@import "one.css" (min-width: 700px) and (orientation: landscape);';
var loader = new StyleInliner(xhr);
var loadedCss = loader.inlineImports(css);
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
@ -136,9 +168,31 @@ export function main() {
}
);
});
});
describe('url rewritting', () => {
it('should rewrite url in inlined content', (done) => {
// it should rewrite both '@import' and 'url()'
xhr.reply('http://base/one.css', '@import "./nested/two.css";.one {background-image: url("one.jpg");}');
xhr.reply('http://base/nested/two.css', '.two {background-image: url("../img/two.jpg");}');
var css = '@import "one.css";'
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual(
".two {background-image: url('http://base/img/two.jpg');}\n" +
".one {background-image: url('http://base/one.jpg');}\n"
);
done();
},
function(e) {
throw 'fail;'
}
);
});
});
});
}

View File

@ -12,20 +12,24 @@ export function main() {
@import "2.css";
@import url('3.css');
@import url("4.css");
@import url(5.css);
.foo {
background-image: url("double.jpg");
background-image: url('simple.jpg');
background-image: url(noquote.jpg);
}`;
var expectedCss = `
@import 'base/1.css';
@import 'base/2.css';
@import url('base/3.css');
@import url('base/4.css');
@import url('base/5.css');
.foo {
background-image: url('base/double.jpg');
background-image: url('base/simple.jpg');
background-image: url('base/noquote.jpg');
}`;
var resolvedCss = styleUrlResolver.resolveUrls(css, 'base');

View File

@ -1,6 +1,7 @@
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/test_lib';
import {TemplateLoader} from 'angular2/src/core/compiler/template_loader';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {Template} from 'angular2/src/core/annotations/template';
@ -14,7 +15,7 @@ export function main() {
beforeEach(() => {
xhr = new XHRMock()
loader = new TemplateLoader(xhr);
loader = new TemplateLoader(xhr, new FakeUrlResolver());
});
it('should load inline templates synchronously', () => {
@ -23,8 +24,9 @@ export function main() {
});
it('should load templates through XHR', (done) => {
xhr.expect('/foo', 'xhr template');
xhr.expect('base/foo', 'xhr template');
var template = new Template({url: '/foo'});
loader.setBaseUrl(template, 'base');
loader.load(template).then((el) => {
expect(el.content).toHaveText('xhr template');
done();
@ -34,8 +36,9 @@ export function main() {
it('should cache template loaded through XHR', (done) => {
var firstEl;
xhr.expect('/foo', 'xhr template');
xhr.expect('base/foo', 'xhr template');
var template = new Template({url: '/foo'});
loader.setBaseUrl(template, 'base');
loader.load(template)
.then((el) => {
firstEl = el;
@ -56,12 +59,13 @@ export function main() {
});
it('should return a rejected Promise when xhr loading fails', (done) => {
xhr.expect('/foo', null);
xhr.expect('base/foo', null);
var template = new Template({url: '/foo'});
loader.setBaseUrl(template, 'base');
PromiseWrapper.then(loader.load(template),
function(_) { throw 'Unexpected response'; },
function(error) {
expect(error).toEqual('Failed to load /foo');
expect(error).toEqual('Failed to load base/foo');
done();
}
)
@ -73,3 +77,13 @@ export function main() {
class SomeComponent {
}
class FakeUrlResolver extends UrlResolver {
constructor() {
super();
}
resolve(baseUrl: string, url: string): string {
return baseUrl + url;
}
}

View File

@ -69,7 +69,8 @@ export function main() {
dom = el(`<div><stuff></stuff><div insert-after-me></div><stuff></stuff></div>`);
var insertionElement = dom.childNodes[1];
parentView = createView([dom.childNodes[0]]);
protoView = new ProtoView(el('<div>hi</div>'), new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy());
protoView = new ProtoView(el('<div>hi</div>'), new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null));
elementInjector = new ElementInjector(null, null, null, null);
viewContainer = new ViewContainer(parentView, insertionElement, protoView, elementInjector, null);
customViewWithOneNode = createView([el('<div>single</div>')]);
@ -213,7 +214,7 @@ export function main() {
viewContainer.hydrate(new Injector([]), null);
var pv = new ProtoView(el('<div class="ng-binding">{{}}</div>'),
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy());
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
pv.bindElement(new ProtoElementInjector(null, 1, [SomeDirective]));
pv.bindTextNode(0, parser.parseBinding('foo', null));
fancyView = pv.instantiate(null, null);

View File

@ -195,7 +195,7 @@ export function main() {
it('should be supported.', () => {
var template = el('<div></div>');
var pv = new ProtoView(template, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy());
new NativeShadowDomStrategy(null));
pv.instantiateInPlace = true;
var view = pv.instantiate(null, null);
view.hydrate(null, null, null);
@ -205,7 +205,7 @@ export function main() {
it('should be off by default.', () => {
var template = el('<div></div>')
var view = new ProtoView(template, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy())
new NativeShadowDomStrategy(null))
.instantiate(null, null);
view.hydrate(null, null, null);
expect(view.nodes[0]).not.toBe(template);
@ -312,7 +312,7 @@ export function main() {
function createComponentWithSubPV(subProtoView) {
var pv = new ProtoView(el('<cmp class="ng-binding"></cmp>'),
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy());
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeComponent], true));
binder.componentDirective = someComponentDirective;
binder.nestedProtoView = subProtoView;
@ -396,7 +396,7 @@ export function main() {
new DynamicProtoChangeDetector(null), null);
var pv = new ProtoView(el('<cmp class="ng-binding"></cmp>'),
new DynamicProtoChangeDetector(null), new EmulatedShadowDomStrategy());
new DynamicProtoChangeDetector(null), new EmulatedShadowDomStrategy(null, null, null));
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeComponent], true));
binder.componentDirective = new DirectiveMetadataReader().read(SomeComponent);
binder.nestedProtoView = subpv;
@ -412,7 +412,7 @@ export function main() {
var templateProtoView = new ProtoView(
el('<div id="1"></div>'), new DynamicProtoChangeDetector(null), null);
var pv = new ProtoView(el('<someTmpl class="ng-binding"></someTmpl>'),
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy());
new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy(null));
var binder = pv.bindElement(new ProtoElementInjector(null, 0, [SomeViewport]));
binder.viewportDirective = someViewportDirective;
binder.nestedProtoView = templateProtoView;
@ -606,12 +606,13 @@ export function main() {
beforeEach(() => {
element = DOM.createElement('div');
pv = new ProtoView(el('<div>hi</div>'), new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy());
new NativeShadowDomStrategy(null));
});
it('should create the root component when instantiated', () => {
var rootProtoView = ProtoView.createRootProtoView(pv, element,
someComponentDirective, new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy());
someComponentDirective, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null));
var view = rootProtoView.instantiate(null, null);
view.hydrate(new Injector([]), null, null);
expect(view.rootElementInjectors[0].get(SomeComponent)).not.toBe(null);
@ -619,7 +620,8 @@ export function main() {
it('should inject the protoView into the shadowDom', () => {
var rootProtoView = ProtoView.createRootProtoView(pv, element,
someComponentDirective, new DynamicProtoChangeDetector(null), new NativeShadowDomStrategy());
someComponentDirective, new DynamicProtoChangeDetector(null),
new NativeShadowDomStrategy(null));
var view = rootProtoView.instantiate(null, null);
view.hydrate(new Injector([]), null, null);
expect(element.shadowRoot.childNodes[0].childNodes[0].nodeValue).toEqual('hi');