refactor(compiler): use the new compiler everywhere
Closes #3605 BREAKING CHANGE: - we don't mark an element as bound any more if it only contains text bindings E.g. <div>{{hello}}</div> This changes the indices when using `DebugElement.componentViewChildren` / `DebugElement.children`. - `@Directive.compileChildren` was removed, `ng-non-bindable` is now builtin and not a directive any more - angular no more adds the `ng-binding` class to elements with bindings - directives are now ordered as they are listed in the View.directives regarding change detection. Previously they had an undefined order. - the `Renderer` interface has new methods `createProtoView` and `registerComponentTemplate`. See `DomRenderer` for default implementations. - reprojection with `ng-content` is now all or nothing per `ng-content` element - angular2 transformer can't be used in tests that modify directive metadata. Use `angular2/src/transform/inliner_for_test` transformer instead.
This commit is contained in:
@@ -101,8 +101,8 @@ export function main() {
|
||||
|
||||
PromiseWrapper.then(refPromise, null, (exception) => {
|
||||
expect(exception).toContainError(
|
||||
`Could not load '${stringify(HelloRootDirectiveIsNotCmp)}' because it is not a component.`);
|
||||
expect(logger.res.join("")).toContain("Could not load");
|
||||
`Could not compile '${stringify(HelloRootDirectiveIsNotCmp)}' because it is not a component.`);
|
||||
expect(logger.res.join("")).toContain("Could not compile");
|
||||
async.done();
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library angular2.src.transform.di_transformer;
|
||||
library angular2.test.core.change_detection.generator;
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
@@ -1,752 +1,63 @@
|
||||
import {
|
||||
AsyncTestCompleter,
|
||||
beforeEach,
|
||||
xdescribe,
|
||||
ddescribe,
|
||||
describe,
|
||||
el,
|
||||
expect,
|
||||
xdescribe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
AsyncTestCompleter,
|
||||
inject,
|
||||
it
|
||||
beforeEachBindings
|
||||
} from 'angular2/test_lib';
|
||||
import {SpyRenderCompiler, SpyDirectiveResolver} from '../spies';
|
||||
import {ListWrapper, Map, MapWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {Type, isBlank, stringify, isPresent, isArray} from 'angular2/src/core/facade/lang';
|
||||
import {PromiseCompleter, PromiseWrapper, Promise} from 'angular2/src/core/facade/async';
|
||||
|
||||
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
||||
import {AppProtoView} from 'angular2/src/core/compiler/view';
|
||||
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
|
||||
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
|
||||
import {PipeResolver} from 'angular2/src/core/compiler/pipe_resolver';
|
||||
import {Attribute, ViewMetadata, Component, Directive, Pipe} from 'angular2/src/core/metadata';
|
||||
import {internalProtoView} from 'angular2/src/core/compiler/view_ref';
|
||||
import {DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
|
||||
import {ViewResolver} from 'angular2/src/core/compiler/view_resolver';
|
||||
import {Component, View, bind} from 'angular2/core';
|
||||
import {SpyProtoViewFactory} from '../spies';
|
||||
import {
|
||||
ComponentUrlMapper,
|
||||
RuntimeComponentUrlMapper
|
||||
} from 'angular2/src/core/compiler/component_url_mapper';
|
||||
CompiledHostTemplate,
|
||||
CompiledTemplate,
|
||||
BeginComponentCmd
|
||||
} from 'angular2/src/core/compiler/template_commands';
|
||||
import {Compiler} from 'angular2/src/core/compiler/compiler';
|
||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
|
||||
import {UrlResolver} from 'angular2/src/core/services/url_resolver';
|
||||
import {AppRootUrl} from 'angular2/src/core/services/app_root_url';
|
||||
import {
|
||||
ProtoViewDto,
|
||||
ViewType,
|
||||
RenderProtoViewRef,
|
||||
ViewDefinition,
|
||||
RenderProtoViewMergeMapping,
|
||||
RenderDirectiveMetadata,
|
||||
DirectiveBinder,
|
||||
RenderElementBinder
|
||||
} from 'angular2/src/core/render/api';
|
||||
// TODO(tbosch): Spys don't support named modules...
|
||||
import {PipeBinding} from 'angular2/src/core/pipes/pipe_binding';
|
||||
|
||||
|
||||
import {reflector, ReflectionInfo} from 'angular2/src/core/reflection/reflection';
|
||||
import {AppProtoView} from 'angular2/src/core/compiler/view';
|
||||
|
||||
export function main() {
|
||||
describe('compiler', function() {
|
||||
var directiveResolver, pipeResolver, tplResolver, renderCompiler, protoViewFactory,
|
||||
cmpUrlMapper, rootProtoView;
|
||||
var renderCompileRequests: any[];
|
||||
describe('Compiler', () => {
|
||||
var compiler: Compiler;
|
||||
var protoViewFactorySpy;
|
||||
var someProtoView;
|
||||
var cht: CompiledHostTemplate;
|
||||
|
||||
function createCompiler(renderCompileResults: Array<ProtoViewDto | Promise<ProtoViewDto>>,
|
||||
protoViewFactoryResults: AppProtoView[]) {
|
||||
var urlResolver = new UrlResolver();
|
||||
renderCompileRequests = [];
|
||||
renderCompileResults = ListWrapper.clone(renderCompileResults);
|
||||
renderCompiler.spy('compile').andCallFake((view) => {
|
||||
renderCompileRequests.push(view);
|
||||
return PromiseWrapper.resolve(ListWrapper.removeAt(renderCompileResults, 0));
|
||||
});
|
||||
|
||||
protoViewFactory = new FakeProtoViewFactory(protoViewFactoryResults);
|
||||
return new Compiler(directiveResolver, pipeResolver, [SomeDefaultPipe], new CompilerCache(),
|
||||
tplResolver, cmpUrlMapper, urlResolver, renderCompiler, protoViewFactory,
|
||||
new AppRootUrl("http://www.app.com"));
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
directiveResolver = new DirectiveResolver();
|
||||
pipeResolver = new PipeResolver();
|
||||
tplResolver = new FakeViewResolver();
|
||||
cmpUrlMapper = new RuntimeComponentUrlMapper();
|
||||
renderCompiler = new SpyRenderCompiler();
|
||||
renderCompiler.spy('compileHost')
|
||||
.andCallFake((componentId) => {
|
||||
return PromiseWrapper.resolve(
|
||||
createRenderProtoView([createRenderComponentElementBinder(0)], ViewType.HOST));
|
||||
});
|
||||
renderCompiler.spy('mergeProtoViewsRecursively')
|
||||
.andCallFake((protoViewRefs: Array<RenderProtoViewRef | any[]>) => {
|
||||
return PromiseWrapper.resolve(new RenderProtoViewMergeMapping(
|
||||
new MergedRenderProtoViewRef(protoViewRefs), 1, [], 0, [], [], [null]));
|
||||
});
|
||||
// TODO spy on .compile and return RenderProtoViewRef, same for compileHost
|
||||
rootProtoView = createRootProtoView(directiveResolver, MainComponent);
|
||||
beforeEachBindings(() => {
|
||||
protoViewFactorySpy = new SpyProtoViewFactory();
|
||||
someProtoView = new AppProtoView(null, null, null, null, null, null);
|
||||
protoViewFactorySpy.spy('createHost').andReturn(someProtoView);
|
||||
return [bind(ProtoViewFactory).toValue(protoViewFactorySpy), Compiler];
|
||||
});
|
||||
|
||||
describe('serialize template', () => {
|
||||
beforeEach(inject([Compiler], (_compiler) => {
|
||||
compiler = _compiler;
|
||||
cht = new CompiledHostTemplate(() => new CompiledTemplate(23, null));
|
||||
reflector.registerType(SomeComponent, new ReflectionInfo([cht]));
|
||||
}));
|
||||
|
||||
function captureTemplate(template: ViewMetadata): Promise<ViewDefinition> {
|
||||
tplResolver.setView(MainComponent, template);
|
||||
var compiler =
|
||||
createCompiler([createRenderProtoView()], [rootProtoView, createProtoView()]);
|
||||
return compiler.compileInHost(MainComponent)
|
||||
.then((_) => {
|
||||
expect(renderCompileRequests.length).toBe(1);
|
||||
return renderCompileRequests[0];
|
||||
});
|
||||
}
|
||||
|
||||
function captureDirective(directive): Promise<RenderDirectiveMetadata> {
|
||||
return captureTemplate(new ViewMetadata({template: '<div></div>', directives: [directive]}))
|
||||
.then((renderTpl) => {
|
||||
expect(renderTpl.directives.length).toBe(1);
|
||||
return renderTpl.directives[0];
|
||||
});
|
||||
}
|
||||
|
||||
it('should fill the componentId', inject([AsyncTestCompleter], (async) => {
|
||||
captureTemplate(new ViewMetadata({template: '<div></div>'}))
|
||||
.then((renderTpl) => {
|
||||
expect(renderTpl.componentId).toEqual(stringify(MainComponent));
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fill inline template', inject([AsyncTestCompleter], (async) => {
|
||||
captureTemplate(new ViewMetadata({template: '<div></div>'}))
|
||||
.then((renderTpl) => {
|
||||
expect(renderTpl.template).toEqual('<div></div>');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fill templateAbsUrl given inline templates',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp/main.js');
|
||||
captureTemplate(new ViewMetadata({template: '<div></div>'}))
|
||||
.then((renderTpl) => {
|
||||
expect(renderTpl.templateAbsUrl).toEqual('http://www.app.com/cmp/main.js');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not fill templateAbsUrl given no inline template or template url',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp/main.js');
|
||||
captureTemplate(new ViewMetadata({template: null, templateUrl: null}))
|
||||
.then((renderTpl) => {
|
||||
expect(renderTpl.templateAbsUrl).toBe(null);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not fill templateAbsUrl given template url with empty string',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp/main.js');
|
||||
captureTemplate(new ViewMetadata({template: null, templateUrl: ''}))
|
||||
.then((renderTpl) => {
|
||||
expect(renderTpl.templateAbsUrl).toBe(null);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not fill templateAbsUrl given template url with blank string',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp/main.js');
|
||||
captureTemplate(new ViewMetadata({template: null, templateUrl: ' '}))
|
||||
.then((renderTpl) => {
|
||||
expect(renderTpl.templateAbsUrl).toBe(null);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fill templateAbsUrl given url template', inject([AsyncTestCompleter], (async) => {
|
||||
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp/main.js');
|
||||
captureTemplate(new ViewMetadata({templateUrl: 'tpl/main.html'}))
|
||||
.then((renderTpl) => {
|
||||
expect(renderTpl.templateAbsUrl).toEqual('http://www.app.com/cmp/tpl/main.html');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fill styleAbsUrls given styleUrls', inject([AsyncTestCompleter], (async) => {
|
||||
cmpUrlMapper.setComponentUrl(MainComponent, '/cmp/main.js');
|
||||
captureTemplate(new ViewMetadata({styleUrls: ['css/1.css', 'css/2.css']}))
|
||||
.then((renderTpl) => {
|
||||
expect(renderTpl.styleAbsUrls)
|
||||
.toEqual(
|
||||
['http://www.app.com/cmp/css/1.css', 'http://www.app.com/cmp/css/2.css']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fill directive.id', inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(MainComponent)
|
||||
.then((renderDir) => {
|
||||
expect(renderDir.id).toEqual(stringify(MainComponent));
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fill directive.selector', inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(MainComponent)
|
||||
.then((renderDir) => {
|
||||
expect(renderDir.selector).toEqual('main-comp');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fill directive.type for components', inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(MainComponent)
|
||||
.then((renderDir) => {
|
||||
expect(renderDir.type).toEqual(RenderDirectiveMetadata.COMPONENT_TYPE);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fill directive.type for dynamic components',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(SomeDynamicComponentDirective)
|
||||
.then((renderDir) => {
|
||||
expect(renderDir.type).toEqual(RenderDirectiveMetadata.COMPONENT_TYPE);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fill directive.type for decorator directives',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(SomeDirective)
|
||||
.then((renderDir) => {
|
||||
expect(renderDir.type).toEqual(RenderDirectiveMetadata.DIRECTIVE_TYPE);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should set directive.compileChildren to false for other directives',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(MainComponent)
|
||||
.then((renderDir) => {
|
||||
expect(renderDir.compileChildren).toEqual(true);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should set directive.compileChildren to true for decorator directives',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(SomeDirective)
|
||||
.then((renderDir) => {
|
||||
expect(renderDir.compileChildren).toEqual(true);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should set directive.compileChildren to false for decorator directives',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(IgnoreChildrenDirective)
|
||||
.then((renderDir) => {
|
||||
expect(renderDir.compileChildren).toEqual(false);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should set directive.hostListeners', inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(DirectiveWithEvents)
|
||||
.then((renderDir) => {
|
||||
expect(renderDir.hostListeners)
|
||||
.toEqual(MapWrapper.createFromStringMap({'someEvent': 'someAction'}));
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should set directive.hostProperties', inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(DirectiveWithProperties)
|
||||
.then((renderDir) => {
|
||||
expect(renderDir.hostProperties)
|
||||
.toEqual(MapWrapper.createFromStringMap({'someProp': 'someExp'}));
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should set directive.bind', inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(DirectiveWithBind)
|
||||
.then((renderDir) => {
|
||||
expect(renderDir.inputs).toEqual(['a: b']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should read @Attribute', inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(DirectiveWithAttributes)
|
||||
.then((renderDir) => {
|
||||
expect(renderDir.readAttributes).toEqual(['someAttr']);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('call ProtoViewFactory', () => {
|
||||
|
||||
it('should pass the ProtoViewDto', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
var renderProtoView = createRenderProtoView();
|
||||
var expectedProtoView = createProtoView();
|
||||
var compiler = createCompiler([renderProtoView], [rootProtoView, expectedProtoView]);
|
||||
compiler.compileInHost(MainComponent)
|
||||
.then((_) => {
|
||||
var request = protoViewFactory.requests[1];
|
||||
expect(request[1]).toBe(renderProtoView);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should pass the component binding', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
var compiler =
|
||||
createCompiler([createRenderProtoView()], [rootProtoView, createProtoView()]);
|
||||
compiler.compileInHost(MainComponent)
|
||||
.then((_) => {
|
||||
var request = protoViewFactory.requests[1];
|
||||
expect(request[0].key.token).toBe(MainComponent);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should pass the directive bindings', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(
|
||||
MainComponent,
|
||||
new ViewMetadata({template: '<div></div>', directives: [SomeDirective]}));
|
||||
var compiler =
|
||||
createCompiler([createRenderProtoView()], [rootProtoView, createProtoView()]);
|
||||
compiler.compileInHost(MainComponent)
|
||||
.then((_) => {
|
||||
var request = protoViewFactory.requests[1];
|
||||
var binding = request[2][0];
|
||||
expect(binding.key.token).toBe(SomeDirective);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should pass the pipe bindings', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent,
|
||||
new ViewMetadata({template: '<div></div>', pipes: [SomePipe]}));
|
||||
var compiler =
|
||||
createCompiler([createRenderProtoView()], [rootProtoView, createProtoView()]);
|
||||
compiler.compileInHost(MainComponent)
|
||||
.then((_) => {
|
||||
var request = protoViewFactory.requests[1];
|
||||
expect(request[3][0].key.token).toBe(SomeDefaultPipe);
|
||||
expect(request[3][1].key.token).toBe(SomePipe);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should use the protoView of the ProtoViewFactory',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
var compiler =
|
||||
createCompiler([createRenderProtoView()], [rootProtoView, createProtoView()]);
|
||||
compiler.compileInHost(MainComponent)
|
||||
.then((protoViewRef) => {
|
||||
expect(internalProtoView(protoViewRef)).toBe(rootProtoView);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
it('should load nested components', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
tplResolver.setView(NestedComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
var mainProtoView =
|
||||
createProtoView([createComponentElementBinder(directiveResolver, NestedComponent)]);
|
||||
var nestedProtoView = createProtoView();
|
||||
var renderPvDtos = [
|
||||
createRenderProtoView([createRenderComponentElementBinder(0)]),
|
||||
createRenderProtoView()
|
||||
];
|
||||
var compiler =
|
||||
createCompiler(renderPvDtos, [rootProtoView, mainProtoView, nestedProtoView]);
|
||||
compiler.compileInHost(MainComponent)
|
||||
.then((protoViewRef) => {
|
||||
expect(originalRenderProtoViewRefs(internalProtoView(protoViewRef)))
|
||||
.toEqual(
|
||||
[rootProtoView.render, [mainProtoView.render, [nestedProtoView.render]]]);
|
||||
expect(internalProtoView(protoViewRef).elementBinders[0].nestedProtoView)
|
||||
.toBe(mainProtoView);
|
||||
expect(mainProtoView.elementBinders[0].nestedProtoView).toBe(nestedProtoView);
|
||||
it('should read the template from an annotation', inject([AsyncTestCompleter], (async) => {
|
||||
compiler.compileInHost(SomeComponent)
|
||||
.then((_) => {
|
||||
expect(protoViewFactorySpy.spy('createHost')).toHaveBeenCalledWith(cht);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should load nested components in viewcontainers', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
tplResolver.setView(NestedComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
var viewportProtoView = createProtoView(
|
||||
[createComponentElementBinder(directiveResolver, NestedComponent)], ViewType.EMBEDDED);
|
||||
var mainProtoView = createProtoView([createViewportElementBinder(viewportProtoView)]);
|
||||
var nestedProtoView = createProtoView();
|
||||
var renderPvDtos = [
|
||||
createRenderProtoView([
|
||||
createRenderViewportElementBinder(
|
||||
createRenderProtoView([createRenderComponentElementBinder(0)], ViewType.EMBEDDED))
|
||||
]),
|
||||
createRenderProtoView()
|
||||
];
|
||||
var compiler =
|
||||
createCompiler(renderPvDtos, [rootProtoView, mainProtoView, nestedProtoView]);
|
||||
compiler.compileInHost(MainComponent)
|
||||
.then((protoViewRef) => {
|
||||
expect(internalProtoView(protoViewRef).elementBinders[0].nestedProtoView)
|
||||
.toBe(mainProtoView);
|
||||
expect(originalRenderProtoViewRefs(internalProtoView(protoViewRef)))
|
||||
.toEqual([rootProtoView.render, [mainProtoView.render, null]]);
|
||||
expect(viewportProtoView.elementBinders[0].nestedProtoView).toBe(nestedProtoView);
|
||||
expect(originalRenderProtoViewRefs(viewportProtoView))
|
||||
.toEqual([viewportProtoView.render, [nestedProtoView.render]]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should cache compiled host components', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
var mainPv = createProtoView();
|
||||
var compiler = createCompiler([createRenderProtoView([])], [rootProtoView, mainPv]);
|
||||
compiler.compileInHost(MainComponent)
|
||||
.then((protoViewRef) => {
|
||||
expect(internalProtoView(protoViewRef).elementBinders[0].nestedProtoView)
|
||||
.toBe(mainPv);
|
||||
return compiler.compileInHost(MainComponent);
|
||||
})
|
||||
.then((protoViewRef) => {
|
||||
expect(internalProtoView(protoViewRef).elementBinders[0].nestedProtoView)
|
||||
.toBe(mainPv);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not bind directives for cached components', inject([AsyncTestCompleter], (async) => {
|
||||
// set up the cache with the test proto view
|
||||
var mainPv: AppProtoView = createProtoView();
|
||||
var cache: CompilerCache = new CompilerCache();
|
||||
cache.setHost(MainComponent, mainPv);
|
||||
|
||||
// create the spy resolver
|
||||
var reader: any = new SpyDirectiveResolver();
|
||||
|
||||
// create the compiler
|
||||
var compiler = new Compiler(reader, pipeResolver, [], cache, tplResolver, cmpUrlMapper,
|
||||
new UrlResolver(), renderCompiler, protoViewFactory,
|
||||
new AppRootUrl("http://www.app.com"));
|
||||
compiler.compileInHost(MainComponent)
|
||||
.then((protoViewRef) => {
|
||||
// the test should have failed if the resolver was called, so we're good
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
it('should cache compiled nested components', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
tplResolver.setView(MainComponent2, new ViewMetadata({template: '<div></div>'}));
|
||||
tplResolver.setView(NestedComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
var rootProtoView2 = createRootProtoView(directiveResolver, MainComponent2);
|
||||
var mainPv =
|
||||
createProtoView([createComponentElementBinder(directiveResolver, NestedComponent)]);
|
||||
var nestedPv = createProtoView([]);
|
||||
var compiler = createCompiler(
|
||||
[createRenderProtoView(), createRenderProtoView(), createRenderProtoView()],
|
||||
[rootProtoView, mainPv, nestedPv, rootProtoView2, mainPv]);
|
||||
compiler.compileInHost(MainComponent)
|
||||
.then((protoViewRef) => {
|
||||
expect(internalProtoView(protoViewRef)
|
||||
.elementBinders[0]
|
||||
.nestedProtoView.elementBinders[0]
|
||||
.nestedProtoView)
|
||||
.toBe(nestedPv);
|
||||
return compiler.compileInHost(MainComponent2);
|
||||
})
|
||||
.then((protoViewRef) => {
|
||||
expect(internalProtoView(protoViewRef)
|
||||
.elementBinders[0]
|
||||
.nestedProtoView.elementBinders[0]
|
||||
.nestedProtoView)
|
||||
.toBe(nestedPv);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should re-use components being compiled', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
var renderProtoViewCompleter: PromiseCompleter<ProtoViewDto> = PromiseWrapper.completer();
|
||||
var expectedProtoView = createProtoView();
|
||||
var compiler = createCompiler([renderProtoViewCompleter.promise],
|
||||
[rootProtoView, rootProtoView, expectedProtoView]);
|
||||
var result = PromiseWrapper.all([
|
||||
compiler.compileInHost(MainComponent),
|
||||
compiler.compileInHost(MainComponent),
|
||||
renderProtoViewCompleter.promise
|
||||
]);
|
||||
renderProtoViewCompleter.resolve(createRenderProtoView());
|
||||
result.then((protoViewRefs) => {
|
||||
expect(internalProtoView(protoViewRefs[0]).elementBinders[0].nestedProtoView)
|
||||
.toBe(expectedProtoView);
|
||||
expect(internalProtoView(protoViewRefs[1]).elementBinders[0].nestedProtoView)
|
||||
.toBe(expectedProtoView);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should throw on unconditional recursive components',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
var mainProtoView =
|
||||
createProtoView([createComponentElementBinder(directiveResolver, MainComponent)]);
|
||||
var compiler =
|
||||
createCompiler([createRenderProtoView([createRenderComponentElementBinder(0)])],
|
||||
[rootProtoView, mainProtoView]);
|
||||
PromiseWrapper.catchError(compiler.compileInHost(MainComponent), (e) => {
|
||||
expect(() => { throw e; })
|
||||
.toThrowError(`Unconditional component cycle in ${stringify(MainComponent)}`);
|
||||
async.done();
|
||||
return null;
|
||||
});
|
||||
}));
|
||||
|
||||
it('should allow recursive components that are connected via an embedded ProtoView',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
var viewportProtoView = createProtoView(
|
||||
[createComponentElementBinder(directiveResolver, MainComponent)], ViewType.EMBEDDED);
|
||||
var mainProtoView = createProtoView([createViewportElementBinder(viewportProtoView)]);
|
||||
var renderPvDtos = [
|
||||
createRenderProtoView([
|
||||
createRenderViewportElementBinder(
|
||||
createRenderProtoView([createRenderComponentElementBinder(0)], ViewType.EMBEDDED))
|
||||
]),
|
||||
createRenderProtoView()
|
||||
];
|
||||
var compiler = createCompiler(renderPvDtos, [rootProtoView, mainProtoView]);
|
||||
compiler.compileInHost(MainComponent)
|
||||
.then((protoViewRef) => {
|
||||
expect(internalProtoView(protoViewRef).elementBinders[0].nestedProtoView)
|
||||
.toBe(mainProtoView);
|
||||
expect(mainProtoView.elementBinders[0]
|
||||
.nestedProtoView.elementBinders[0]
|
||||
.nestedProtoView)
|
||||
.toBe(mainProtoView);
|
||||
// In case of a cycle, don't merge the embedded proto views into the component!
|
||||
expect(originalRenderProtoViewRefs(internalProtoView(protoViewRef)))
|
||||
.toEqual([rootProtoView.render, [mainProtoView.render, null]]);
|
||||
expect(originalRenderProtoViewRefs(viewportProtoView))
|
||||
.toEqual([viewportProtoView.render, [mainProtoView.render, null]]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should throw on recursive components that are connected via an embedded ProtoView with <ng-content>',
|
||||
inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
var viewportProtoView =
|
||||
createProtoView([createComponentElementBinder(directiveResolver, MainComponent)],
|
||||
ViewType.EMBEDDED, true);
|
||||
var mainProtoView = createProtoView([createViewportElementBinder(viewportProtoView)]);
|
||||
var renderPvDtos = [
|
||||
createRenderProtoView([
|
||||
createRenderViewportElementBinder(
|
||||
createRenderProtoView([createRenderComponentElementBinder(0)], ViewType.EMBEDDED))
|
||||
]),
|
||||
createRenderProtoView()
|
||||
];
|
||||
var compiler = createCompiler(renderPvDtos, [rootProtoView, mainProtoView]);
|
||||
PromiseWrapper.catchError(compiler.compileInHost(MainComponent), (e) => {
|
||||
expect(() => { throw e; })
|
||||
.toThrowError(
|
||||
`<ng-content> is used within the recursive path of ${stringify(MainComponent)}`);
|
||||
async.done();
|
||||
return null;
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
it('should create host proto views', inject([AsyncTestCompleter], (async) => {
|
||||
tplResolver.setView(MainComponent, new ViewMetadata({template: '<div></div>'}));
|
||||
var rootProtoView = createProtoView(
|
||||
[createComponentElementBinder(directiveResolver, MainComponent)], ViewType.HOST);
|
||||
var mainProtoView = createProtoView();
|
||||
var compiler = createCompiler([createRenderProtoView()], [rootProtoView, mainProtoView]);
|
||||
compiler.compileInHost(MainComponent)
|
||||
.then((protoViewRef) => {
|
||||
expect(internalProtoView(protoViewRef)).toBe(rootProtoView);
|
||||
expect(rootProtoView.elementBinders[0].nestedProtoView).toBe(mainProtoView);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should throw for non component types', () => {
|
||||
var compiler = createCompiler([], []);
|
||||
expect(() => compiler.compileInHost(SomeDirective))
|
||||
.toThrowError(
|
||||
`Could not load '${stringify(SomeDirective)}' because it is not a component.`);
|
||||
it('should clear the cache', () => {
|
||||
compiler.clearCache();
|
||||
expect(protoViewFactorySpy.spy('clearCache')).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createDirectiveBinding(directiveResolver, type): DirectiveBinding {
|
||||
var annotation = directiveResolver.resolve(type);
|
||||
return DirectiveBinding.createFromType(type, annotation);
|
||||
}
|
||||
|
||||
function createProtoView(elementBinders = null, type: ViewType = null,
|
||||
isEmbeddedFragment: boolean = false): AppProtoView {
|
||||
if (isBlank(type)) {
|
||||
type = ViewType.COMPONENT;
|
||||
}
|
||||
var pv = new AppProtoView(type, isEmbeddedFragment, new RenderProtoViewRef(), null, null,
|
||||
new Map<string, number>(), null, null);
|
||||
if (isBlank(elementBinders)) {
|
||||
elementBinders = [];
|
||||
}
|
||||
pv.elementBinders = elementBinders;
|
||||
return pv;
|
||||
}
|
||||
|
||||
function createComponentElementBinder(directiveResolver, type): ElementBinder {
|
||||
var binding = createDirectiveBinding(directiveResolver, type);
|
||||
return new ElementBinder(0, null, 0, null, binding);
|
||||
}
|
||||
|
||||
function createViewportElementBinder(nestedProtoView): ElementBinder {
|
||||
var elBinder = new ElementBinder(0, null, 0, null, null);
|
||||
elBinder.nestedProtoView = nestedProtoView;
|
||||
return elBinder;
|
||||
}
|
||||
|
||||
function createRenderProtoView(elementBinders = null, type: ViewType = null): ProtoViewDto {
|
||||
if (isBlank(type)) {
|
||||
type = ViewType.COMPONENT;
|
||||
}
|
||||
if (isBlank(elementBinders)) {
|
||||
elementBinders = [];
|
||||
}
|
||||
return new ProtoViewDto(
|
||||
{elementBinders: elementBinders, type: type, render: new RenderProtoViewRef()});
|
||||
}
|
||||
|
||||
function createRenderComponentElementBinder(directiveIndex): RenderElementBinder {
|
||||
return new RenderElementBinder(
|
||||
{directives: [new DirectiveBinder({directiveIndex: directiveIndex})]});
|
||||
}
|
||||
|
||||
function createRenderViewportElementBinder(nestedProtoView): RenderElementBinder {
|
||||
return new RenderElementBinder({nestedProtoView: nestedProtoView});
|
||||
}
|
||||
|
||||
function createRootProtoView(directiveResolver, type): AppProtoView {
|
||||
return createProtoView([createComponentElementBinder(directiveResolver, type)], ViewType.HOST);
|
||||
}
|
||||
|
||||
@Component({selector: 'main-comp'})
|
||||
class MainComponent {
|
||||
}
|
||||
|
||||
@Component({selector: 'main-comp2'})
|
||||
class MainComponent2 {
|
||||
}
|
||||
|
||||
@Component({selector: 'nested'})
|
||||
class NestedComponent {
|
||||
}
|
||||
|
||||
class RecursiveComponent {}
|
||||
|
||||
@Component({selector: 'some-dynamic'})
|
||||
class SomeDynamicComponentDirective {
|
||||
}
|
||||
|
||||
@Directive({selector: 'some'})
|
||||
class SomeDirective {
|
||||
}
|
||||
|
||||
@Directive({compileChildren: false})
|
||||
class IgnoreChildrenDirective {
|
||||
}
|
||||
|
||||
@Directive({host: {'(someEvent)': 'someAction'}})
|
||||
class DirectiveWithEvents {
|
||||
}
|
||||
|
||||
@Directive({host: {'[someProp]': 'someExp'}})
|
||||
class DirectiveWithProperties {
|
||||
}
|
||||
|
||||
@Directive({inputs: ['a: b']})
|
||||
class DirectiveWithBind {
|
||||
}
|
||||
|
||||
@Pipe({name: 'some-default-pipe'})
|
||||
class SomeDefaultPipe {
|
||||
}
|
||||
|
||||
@Pipe({name: 'some-pipe'})
|
||||
class SomePipe {
|
||||
}
|
||||
|
||||
@Directive({selector: 'directive-with-accts'})
|
||||
class DirectiveWithAttributes {
|
||||
constructor(@Attribute('someAttr') someAttr: String) {}
|
||||
}
|
||||
|
||||
class FakeViewResolver extends ViewResolver {
|
||||
_cmpViews = new Map<Type, ViewMetadata>();
|
||||
|
||||
constructor() { super(); }
|
||||
|
||||
resolve(component: Type): ViewMetadata {
|
||||
// returns null for dynamic components
|
||||
return this._cmpViews.has(component) ? this._cmpViews.get(component) : null;
|
||||
}
|
||||
|
||||
setView(component: Type, view: ViewMetadata): void { this._cmpViews.set(component, view); }
|
||||
}
|
||||
|
||||
class FakeProtoViewFactory extends ProtoViewFactory {
|
||||
requests: any[][];
|
||||
|
||||
constructor(public results: AppProtoView[]) {
|
||||
super(null);
|
||||
this.requests = [];
|
||||
}
|
||||
|
||||
createAppProtoViews(componentBinding: DirectiveBinding, renderProtoView: ProtoViewDto,
|
||||
directives: DirectiveBinding[], pipes: PipeBinding[]): AppProtoView[] {
|
||||
this.requests.push([componentBinding, renderProtoView, directives, pipes]);
|
||||
return collectEmbeddedPvs(ListWrapper.removeAt(this.results, 0));
|
||||
}
|
||||
}
|
||||
|
||||
class MergedRenderProtoViewRef extends RenderProtoViewRef {
|
||||
constructor(public originals: RenderProtoViewRef[]) { super(); }
|
||||
}
|
||||
|
||||
function originalRenderProtoViewRefs(appProtoView: AppProtoView) {
|
||||
return (<MergedRenderProtoViewRef>appProtoView.mergeMapping.renderProtoViewRef).originals;
|
||||
}
|
||||
|
||||
function collectEmbeddedPvs(pv: AppProtoView, target: AppProtoView[] = null): AppProtoView[] {
|
||||
if (isBlank(target)) {
|
||||
target = [];
|
||||
}
|
||||
target.push(pv);
|
||||
pv.elementBinders.forEach(elementBinder => {
|
||||
if (elementBinder.hasEmbeddedProtoView()) {
|
||||
collectEmbeddedPvs(elementBinder.nestedProtoView, target);
|
||||
}
|
||||
});
|
||||
return target;
|
||||
}
|
||||
class SomeComponent {}
|
||||
|
||||
@@ -111,7 +111,6 @@ export function main() {
|
||||
rootTC.detectChanges();
|
||||
expect(rootTC.debugElement.nativeElement).toHaveText('Hello World!');
|
||||
async.done();
|
||||
|
||||
});
|
||||
}));
|
||||
|
||||
@@ -431,7 +430,7 @@ export function main() {
|
||||
tcb.overrideView(
|
||||
MyComp, new ViewMetadata({
|
||||
template:
|
||||
'<div><template some-viewport var-greeting="some-tmpl"><copy-me>{{greeting}}</copy-me></template></div>',
|
||||
'<template some-viewport var-greeting="some-tmpl"><copy-me>{{greeting}}</copy-me></template>',
|
||||
directives: [SomeViewport]
|
||||
}))
|
||||
|
||||
@@ -440,11 +439,11 @@ export function main() {
|
||||
|
||||
rootTC.detectChanges();
|
||||
|
||||
var childNodesOfWrapper = rootTC.debugElement.componentViewChildren;
|
||||
var childNodesOfWrapper = DOM.childNodes(rootTC.debugElement.nativeElement);
|
||||
// 1 template + 2 copies.
|
||||
expect(childNodesOfWrapper.length).toBe(3);
|
||||
expect(childNodesOfWrapper[1].nativeElement).toHaveText('hello');
|
||||
expect(childNodesOfWrapper[2].nativeElement).toHaveText('again');
|
||||
expect(childNodesOfWrapper[1]).toHaveText('hello');
|
||||
expect(childNodesOfWrapper[2]).toHaveText('again');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
@@ -454,7 +453,7 @@ export function main() {
|
||||
tcb.overrideView(
|
||||
MyComp, new ViewMetadata({
|
||||
template:
|
||||
'<div><copy-me template="some-viewport: var greeting=some-tmpl">{{greeting}}</copy-me></div>',
|
||||
'<copy-me template="some-viewport: var greeting=some-tmpl">{{greeting}}</copy-me>',
|
||||
directives: [SomeViewport]
|
||||
}))
|
||||
|
||||
@@ -462,11 +461,11 @@ export function main() {
|
||||
.then((rootTC) => {
|
||||
rootTC.detectChanges();
|
||||
|
||||
var childNodesOfWrapper = rootTC.debugElement.componentViewChildren;
|
||||
var childNodesOfWrapper = DOM.childNodes(rootTC.debugElement.nativeElement);
|
||||
// 1 template + 2 copies.
|
||||
expect(childNodesOfWrapper.length).toBe(3);
|
||||
expect(childNodesOfWrapper[1].nativeElement).toHaveText('hello');
|
||||
expect(childNodesOfWrapper[2].nativeElement).toHaveText('again');
|
||||
expect(childNodesOfWrapper[1]).toHaveText('hello');
|
||||
expect(childNodesOfWrapper[2]).toHaveText('again');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
@@ -629,7 +628,7 @@ export function main() {
|
||||
tcb.overrideView(
|
||||
MyComp, new ViewMetadata({
|
||||
template:
|
||||
'<div><div *ng-for="var i of [1]"><child-cmp-no-template #cmp></child-cmp-no-template>{{i}}-{{cmp.ctxProp}}</div></div>',
|
||||
'<template ng-for [ng-for-of]="[1]" var-i><child-cmp-no-template #cmp></child-cmp-no-template>{{i}}-{{cmp.ctxProp}}</template>',
|
||||
directives: [ChildCompNoTemplate, NgFor]
|
||||
}))
|
||||
|
||||
@@ -637,8 +636,8 @@ export function main() {
|
||||
.then((rootTC) => {
|
||||
rootTC.detectChanges();
|
||||
|
||||
// Get the element at index 1, since index 0 is the <template>.
|
||||
expect(rootTC.debugElement.componentViewChildren[1].nativeElement)
|
||||
// Get the element at index 2, since index 0 is the <template>.
|
||||
expect(DOM.childNodes(rootTC.debugElement.nativeElement)[2])
|
||||
.toHaveText("1-hello");
|
||||
|
||||
async.done();
|
||||
@@ -1217,8 +1216,9 @@ export function main() {
|
||||
describe("error handling", () => {
|
||||
it('should report a meaningful error when a directive is missing annotation',
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
tcb = tcb.overrideView(MyComp,
|
||||
new ViewMetadata({directives: [SomeDirectiveMissingAnnotation]}));
|
||||
tcb = tcb.overrideView(
|
||||
MyComp,
|
||||
new ViewMetadata({template: '', directives: [SomeDirectiveMissingAnnotation]}));
|
||||
|
||||
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
|
||||
expect(e.message).toEqual(
|
||||
@@ -1229,19 +1229,20 @@ export function main() {
|
||||
}));
|
||||
|
||||
it('should report a meaningful error when a component is missing view annotation',
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
PromiseWrapper.catchError(tcb.createAsync(ComponentWithoutView), (e) => {
|
||||
inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||
try {
|
||||
tcb.createAsync(ComponentWithoutView);
|
||||
} catch (e) {
|
||||
expect(e.message).toEqual(
|
||||
`No View annotation found on component ${stringify(ComponentWithoutView)}`);
|
||||
async.done();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
it('should report a meaningful error when a directive is null',
|
||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||
|
||||
tcb = tcb.overrideView(MyComp, new ViewMetadata({directives: [[null]]}));
|
||||
tcb = tcb.overrideView(MyComp, new ViewMetadata({directives: [[null]], template: ''}));
|
||||
|
||||
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
|
||||
expect(e.message).toEqual(
|
||||
@@ -1353,7 +1354,8 @@ export function main() {
|
||||
|
||||
var undefinedValue;
|
||||
|
||||
tcb = tcb.overrideView(MyComp, new ViewMetadata({directives: [undefinedValue]}));
|
||||
tcb = tcb.overrideView(MyComp,
|
||||
new ViewMetadata({directives: [undefinedValue], template: ''}));
|
||||
|
||||
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
|
||||
expect(e.message).toEqual(
|
||||
@@ -1457,7 +1459,7 @@ export function main() {
|
||||
|
||||
PromiseWrapper.catchError(tcb.createAsync(MyComp), (e) => {
|
||||
expect(e.message).toEqual(
|
||||
`Can't bind to 'unknown' since it isn't a known property of the '<div>' element and there are no matching directives with a corresponding property`);
|
||||
`Template parse errors:\nCan't bind to 'unknown' since it isn't a known native property in MyComp > div:nth-child(0)[unknown={{ctxProp}}]`);
|
||||
async.done();
|
||||
return null;
|
||||
});
|
||||
@@ -1516,9 +1518,8 @@ export function main() {
|
||||
|
||||
describe('logging property updates', () => {
|
||||
beforeEachBindings(() => [
|
||||
bind(ChangeDetection)
|
||||
.toValue(
|
||||
new DynamicChangeDetection(new ChangeDetectorGenConfig(true, true, true, false)))
|
||||
bind(ChangeDetectorGenConfig)
|
||||
.toValue(new ChangeDetectorGenConfig(true, true, true, false))
|
||||
]);
|
||||
|
||||
it('should reflect property values as attributes',
|
||||
|
||||
@@ -522,7 +522,8 @@ class OuterWithIndirectNestedComponent {
|
||||
|
||||
@Component({selector: 'outer'})
|
||||
@View({
|
||||
template: 'OUTER(<inner><ng-content></ng-content></inner>)',
|
||||
template:
|
||||
'OUTER(<inner><ng-content select=".left" class="left"></ng-content><ng-content></ng-content></inner>)',
|
||||
directives: [forwardRef(() => InnerComponent)]
|
||||
})
|
||||
class OuterComponent {
|
||||
@@ -530,7 +531,8 @@ class OuterComponent {
|
||||
|
||||
@Component({selector: 'inner'})
|
||||
@View({
|
||||
template: 'INNER(<innerinner><ng-content></ng-content></innerinner>)',
|
||||
template:
|
||||
'INNER(<innerinner><ng-content select=".left" class="left"></ng-content><ng-content></ng-content></innerinner>)',
|
||||
directives: [forwardRef(() => InnerInnerComponent)]
|
||||
})
|
||||
class InnerComponent {
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
|
||||
import {SpyChangeDetection} from '../spies';
|
||||
import {isBlank, stringify} from 'angular2/src/core/facade/lang';
|
||||
import {MapWrapper} from 'angular2/src/core/facade/collection';
|
||||
|
||||
import {
|
||||
ChangeDetection,
|
||||
@@ -24,10 +23,7 @@ import {
|
||||
} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {
|
||||
BindingRecordsCreator,
|
||||
ProtoViewFactory,
|
||||
getChangeDetectorDefinitions,
|
||||
createDirectiveVariableBindings,
|
||||
createVariableLocations
|
||||
getChangeDetectorDefinitions
|
||||
} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
import {Component, Directive} from 'angular2/src/core/metadata';
|
||||
import {Key, Binding} from 'angular2/core';
|
||||
@@ -43,18 +39,14 @@ import {
|
||||
} from 'angular2/src/core/render/api';
|
||||
|
||||
export function main() {
|
||||
// TODO(tbosch): add missing tests
|
||||
|
||||
describe('ProtoViewFactory', () => {
|
||||
var changeDetection;
|
||||
var protoViewFactory: ProtoViewFactory;
|
||||
var directiveResolver;
|
||||
|
||||
beforeEach(() => {
|
||||
directiveResolver = new DirectiveResolver();
|
||||
changeDetection = new SpyChangeDetection();
|
||||
changeDetection.prop("generateDetectors", true);
|
||||
protoViewFactory = new ProtoViewFactory(changeDetection);
|
||||
});
|
||||
|
||||
function bindDirective(type) {
|
||||
@@ -73,107 +65,6 @@ export function main() {
|
||||
|
||||
});
|
||||
|
||||
describe('createAppProtoViews', () => {
|
||||
|
||||
it('should create an AppProtoView for the root render proto view', () => {
|
||||
var varBindings = new Map();
|
||||
varBindings.set('a', 'b');
|
||||
var renderPv = createRenderProtoView([], null, varBindings);
|
||||
var appPvs =
|
||||
protoViewFactory.createAppProtoViews(bindDirective(MainComponent), renderPv, [], []);
|
||||
expect(appPvs[0].variableBindings.get('a')).toEqual('b');
|
||||
expect(appPvs.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("createDirectiveVariableBindings", () => {
|
||||
it("should calculate directive variable bindings", () => {
|
||||
var dvbs = createDirectiveVariableBindings(
|
||||
new RenderElementBinder({
|
||||
variableBindings:
|
||||
MapWrapper.createFromStringMap<string>({"exportName": "templateName"})
|
||||
}),
|
||||
[
|
||||
directiveBinding(
|
||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'exportName'})}),
|
||||
directiveBinding(
|
||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'otherName'})})
|
||||
]);
|
||||
|
||||
expect(dvbs).toEqual(MapWrapper.createFromStringMap<number>({"templateName": 0}));
|
||||
});
|
||||
|
||||
it("should set exportAs to $implicit for component with exportAs = null", () => {
|
||||
var dvbs = createDirectiveVariableBindings(
|
||||
new RenderElementBinder({
|
||||
variableBindings:
|
||||
MapWrapper.createFromStringMap<string>({"$implicit": "templateName"})
|
||||
}),
|
||||
[
|
||||
directiveBinding({
|
||||
metadata: RenderDirectiveMetadata.create(
|
||||
{exportAs: null, type: RenderDirectiveMetadata.COMPONENT_TYPE})
|
||||
})
|
||||
]);
|
||||
|
||||
expect(dvbs).toEqual(MapWrapper.createFromStringMap<number>({"templateName": 0}));
|
||||
});
|
||||
|
||||
it("should throw we no directive exported with this name", () => {
|
||||
expect(() => {
|
||||
createDirectiveVariableBindings(
|
||||
new RenderElementBinder({
|
||||
variableBindings:
|
||||
MapWrapper.createFromStringMap<string>({"someInvalidName": "templateName"})
|
||||
}),
|
||||
[
|
||||
directiveBinding(
|
||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'exportName'})})
|
||||
]);
|
||||
}).toThrowError(new RegExp("Cannot find directive with exportAs = 'someInvalidName'"));
|
||||
});
|
||||
|
||||
it("should throw when binding to a name exported by two directives", () => {
|
||||
expect(() => {
|
||||
createDirectiveVariableBindings(
|
||||
new RenderElementBinder({
|
||||
variableBindings:
|
||||
MapWrapper.createFromStringMap<string>({"exportName": "templateName"})
|
||||
}),
|
||||
[
|
||||
directiveBinding(
|
||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'exportName'})}),
|
||||
directiveBinding(
|
||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'exportName'})})
|
||||
]);
|
||||
}).toThrowError(new RegExp("More than one directive have exportAs = 'exportName'"));
|
||||
});
|
||||
|
||||
it("should not throw when not binding to a name exported by two directives", () => {
|
||||
expect(() => {
|
||||
createDirectiveVariableBindings(
|
||||
new RenderElementBinder({variableBindings: new Map<string, string>()}), [
|
||||
directiveBinding(
|
||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'exportName'})}),
|
||||
directiveBinding(
|
||||
{metadata: RenderDirectiveMetadata.create({exportAs: 'exportName'})})
|
||||
]);
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('createVariableLocations', () => {
|
||||
it('should merge the names in the template for all ElementBinders', () => {
|
||||
expect(createVariableLocations([
|
||||
new RenderElementBinder(
|
||||
{variableBindings: MapWrapper.createFromStringMap<string>({"x": "a"})}),
|
||||
new RenderElementBinder(
|
||||
{variableBindings: MapWrapper.createFromStringMap<string>({"y": "b"})})
|
||||
|
||||
])).toEqual(MapWrapper.createFromStringMap<number>({'a': 0, 'b': 1}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('BindingRecordsCreator', () => {
|
||||
var creator: BindingRecordsCreator;
|
||||
|
||||
@@ -247,15 +138,6 @@ function createRenderProtoView(elementBinders = null, type: ViewType = null,
|
||||
});
|
||||
}
|
||||
|
||||
function createRenderComponentElementBinder(directiveIndex) {
|
||||
return new RenderElementBinder(
|
||||
{directives: [new DirectiveBinder({directiveIndex: directiveIndex})]});
|
||||
}
|
||||
|
||||
function createRenderViewportElementBinder(nestedProtoView) {
|
||||
return new RenderElementBinder({nestedProtoView: nestedProtoView});
|
||||
}
|
||||
|
||||
@Component({selector: 'main-comp'})
|
||||
class MainComponent {
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export function main() {
|
||||
viewManager = new SpyAppViewManager();
|
||||
view = new SpyView();
|
||||
view.prop("viewContainers", [null]);
|
||||
location = new ElementRef(new ViewRef(view), 0, 0, null);
|
||||
location = new ElementRef(new ViewRef(view), 0, null);
|
||||
});
|
||||
|
||||
describe('length', () => {
|
||||
|
||||
@@ -13,15 +13,10 @@ import {
|
||||
it,
|
||||
xit
|
||||
} from 'angular2/test_lib';
|
||||
import {SpyRenderer, SpyAppViewPool, SpyAppViewListener} from '../spies';
|
||||
import {SpyRenderer, SpyAppViewPool, SpyAppViewListener, SpyProtoViewFactory} from '../spies';
|
||||
import {Injector, bind} from 'angular2/core';
|
||||
|
||||
import {
|
||||
AppProtoView,
|
||||
AppView,
|
||||
AppViewContainer,
|
||||
AppProtoViewMergeMapping
|
||||
} from 'angular2/src/core/compiler/view';
|
||||
import {AppProtoView, AppView, AppViewContainer} from 'angular2/src/core/compiler/view';
|
||||
import {ProtoViewRef, ViewRef, internalView} from 'angular2/src/core/compiler/view_ref';
|
||||
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
||||
import {TemplateRef} from 'angular2/src/core/compiler/template_ref';
|
||||
@@ -54,6 +49,7 @@ export function main() {
|
||||
var utils: AppViewManagerUtils;
|
||||
var viewListener;
|
||||
var viewPool;
|
||||
var linker;
|
||||
var manager: AppViewManager;
|
||||
var createdRenderViews: RenderViewWithFragments[];
|
||||
|
||||
@@ -78,7 +74,8 @@ export function main() {
|
||||
utils = new AppViewManagerUtils();
|
||||
viewListener = new SpyAppViewListener();
|
||||
viewPool = new SpyAppViewPool();
|
||||
manager = new AppViewManager(viewPool, viewListener, utils, renderer);
|
||||
linker = new SpyProtoViewFactory();
|
||||
manager = new AppViewManager(viewPool, viewListener, utils, renderer, linker);
|
||||
createdRenderViews = [];
|
||||
|
||||
renderer.spy('createRootHostView')
|
||||
@@ -110,6 +107,11 @@ export function main() {
|
||||
beforeEach(
|
||||
() => { hostProtoView = createHostPv([createNestedElBinder(createComponentPv())]); });
|
||||
|
||||
it('should initialize the ProtoView', () => {
|
||||
manager.createRootHostView(wrapPv(hostProtoView), null, null);
|
||||
expect(linker.spy('initializeProtoViewIfNeeded')).toHaveBeenCalledWith(hostProtoView);
|
||||
});
|
||||
|
||||
it('should create the view', () => {
|
||||
var rootView =
|
||||
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
|
||||
@@ -129,8 +131,8 @@ export function main() {
|
||||
var rootView =
|
||||
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), null, null));
|
||||
expect(renderer.spy('createRootHostView'))
|
||||
.toHaveBeenCalledWith(hostProtoView.mergeMapping.renderProtoViewRef,
|
||||
hostProtoView.mergeMapping.renderFragmentCount, 'someComponent');
|
||||
.toHaveBeenCalledWith(hostProtoView.render,
|
||||
hostProtoView.mergeInfo.embeddedViewCount + 1, 'someComponent');
|
||||
expect(rootView.render).toBe(createdRenderViews[0].viewRef);
|
||||
expect(rootView.renderFragment).toBe(createdRenderViews[0].fragmentRefs[0]);
|
||||
});
|
||||
@@ -139,8 +141,8 @@ export function main() {
|
||||
var selector = 'someOtherSelector';
|
||||
internalView(<ViewRef>manager.createRootHostView(wrapPv(hostProtoView), selector, null));
|
||||
expect(renderer.spy('createRootHostView'))
|
||||
.toHaveBeenCalledWith(hostProtoView.mergeMapping.renderProtoViewRef,
|
||||
hostProtoView.mergeMapping.renderFragmentCount, selector);
|
||||
.toHaveBeenCalledWith(hostProtoView.render,
|
||||
hostProtoView.mergeInfo.embeddedViewCount + 1, selector);
|
||||
});
|
||||
|
||||
it('should set the event dispatcher', () => {
|
||||
@@ -182,7 +184,7 @@ export function main() {
|
||||
|
||||
});
|
||||
|
||||
describe('createViewInContainer', () => {
|
||||
describe('createEmbeddedViewInContainer', () => {
|
||||
|
||||
describe('basic functionality', () => {
|
||||
var hostView: AppView;
|
||||
@@ -200,6 +202,11 @@ export function main() {
|
||||
resetSpies();
|
||||
});
|
||||
|
||||
it('should initialize the ProtoView', () => {
|
||||
manager.createEmbeddedViewInContainer(vcRef, 0, templateRef);
|
||||
expect(linker.spy('initializeProtoViewIfNeeded')).toHaveBeenCalledWith(childProtoView);
|
||||
});
|
||||
|
||||
describe('create the first view', () => {
|
||||
|
||||
it('should create an AppViewContainer if not yet existing', () => {
|
||||
@@ -255,8 +262,8 @@ export function main() {
|
||||
expect(childView).not.toBe(firstChildView);
|
||||
expect(viewListener.spy('viewCreated')).toHaveBeenCalledWith(childView);
|
||||
expect(renderer.spy('createView'))
|
||||
.toHaveBeenCalledWith(childProtoView.mergeMapping.renderProtoViewRef,
|
||||
childProtoView.mergeMapping.renderFragmentCount);
|
||||
.toHaveBeenCalledWith(childProtoView.render,
|
||||
childProtoView.mergeInfo.embeddedViewCount + 1);
|
||||
expect(childView.render).toBe(createdRenderViews[1].viewRef);
|
||||
expect(childView.renderFragment).toBe(createdRenderViews[1].fragmentRefs[0]);
|
||||
});
|
||||
@@ -306,6 +313,12 @@ export function main() {
|
||||
|
||||
describe('create a host view', () => {
|
||||
|
||||
it('should initialize the ProtoView', () => {
|
||||
var newHostPv = createHostPv([createNestedElBinder(createComponentPv())]);
|
||||
manager.createHostViewInContainer(vcRef, 0, wrapPv(newHostPv), null);
|
||||
expect(linker.spy('initializeProtoViewIfNeeded')).toHaveBeenCalledWith(newHostPv);
|
||||
});
|
||||
|
||||
it('should always create a new view and not use the embedded view', () => {
|
||||
var newHostPv = createHostPv([createNestedElBinder(createComponentPv())]);
|
||||
var newHostView = internalView(
|
||||
@@ -314,8 +327,7 @@ export function main() {
|
||||
expect(newHostView).not.toBe(hostView.views[2]);
|
||||
expect(viewListener.spy('viewCreated')).toHaveBeenCalledWith(newHostView);
|
||||
expect(renderer.spy('createView'))
|
||||
.toHaveBeenCalledWith(newHostPv.mergeMapping.renderProtoViewRef,
|
||||
newHostPv.mergeMapping.renderFragmentCount);
|
||||
.toHaveBeenCalledWith(newHostPv.render, newHostPv.mergeInfo.embeddedViewCount + 1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
|
||||
import {
|
||||
SpyChangeDetector,
|
||||
SpyProtoChangeDetector,
|
||||
SpyProtoElementInjector,
|
||||
SpyElementInjector,
|
||||
SpyPreBuiltObjects
|
||||
@@ -26,9 +25,8 @@ import {
|
||||
|
||||
import {Injector, bind} from 'angular2/core';
|
||||
import {isBlank, isPresent} from 'angular2/src/core/facade/lang';
|
||||
import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
|
||||
|
||||
import {AppProtoView, AppView, AppProtoViewMergeMapping} from 'angular2/src/core/compiler/view';
|
||||
import {AppProtoView, AppView, AppProtoViewMergeInfo} from 'angular2/src/core/compiler/view';
|
||||
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
|
||||
import {
|
||||
DirectiveBinding,
|
||||
@@ -208,16 +206,19 @@ export function createInjector() {
|
||||
function createElementInjector(parent = null) {
|
||||
var host = new SpyElementInjector();
|
||||
var elementInjector = new SpyElementInjector();
|
||||
var res = SpyObject.stub(elementInjector,
|
||||
{
|
||||
'isExportingComponent': false,
|
||||
'isExportingElement': false,
|
||||
'getEventEmitterAccessors': [],
|
||||
'getHostActionAccessors': [],
|
||||
'getComponent': new Object(),
|
||||
'getHost': host
|
||||
},
|
||||
{});
|
||||
var _preBuiltObjects = null;
|
||||
var res = SpyObject.stub(elementInjector, {
|
||||
'isExportingComponent': false,
|
||||
'isExportingElement': false,
|
||||
'getEventEmitterAccessors': [],
|
||||
'getHostActionAccessors': [],
|
||||
'getComponent': new Object(),
|
||||
'getHost': host
|
||||
});
|
||||
res.spy('getNestedView').andCallFake(() => _preBuiltObjects.nestedView);
|
||||
res.spy('hydrate')
|
||||
.andCallFake((mperativelyCreatedInjector: Injector, host: ElementInjector,
|
||||
preBuiltObjects: PreBuiltObjects) => { _preBuiltObjects = preBuiltObjects; });
|
||||
res.prop('parent', parent);
|
||||
return res;
|
||||
}
|
||||
@@ -232,7 +233,7 @@ export function createProtoElInjector(parent: ProtoElementInjector = null): Prot
|
||||
|
||||
export function createEmptyElBinder(parent: ElementBinder = null) {
|
||||
var parentPeli = isPresent(parent) ? parent.protoElementInjector : null;
|
||||
return new ElementBinder(0, null, 0, createProtoElInjector(parentPeli), null);
|
||||
return new ElementBinder(0, null, 0, createProtoElInjector(parentPeli), null, null);
|
||||
}
|
||||
|
||||
export function createNestedElBinder(nestedProtoView: AppProtoView) {
|
||||
@@ -241,78 +242,35 @@ export function createNestedElBinder(nestedProtoView: AppProtoView) {
|
||||
var annotation = new DirectiveResolver().resolve(SomeComponent);
|
||||
componentBinding = DirectiveBinding.createFromType(SomeComponent, annotation);
|
||||
}
|
||||
var binder = new ElementBinder(0, null, 0, createProtoElInjector(), componentBinding);
|
||||
binder.nestedProtoView = nestedProtoView;
|
||||
return binder;
|
||||
}
|
||||
|
||||
function countNestedElementBinders(pv: AppProtoView): number {
|
||||
var result = pv.elementBinders.length;
|
||||
pv.elementBinders.forEach(binder => {
|
||||
if (isPresent(binder.nestedProtoView)) {
|
||||
result += countNestedElementBinders(binder.nestedProtoView);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function calcHostElementIndicesByViewIndex(pv: AppProtoView, elementOffset = 0,
|
||||
target: number[] = null): number[] {
|
||||
if (isBlank(target)) {
|
||||
target = [null];
|
||||
}
|
||||
for (var binderIdx = 0; binderIdx < pv.elementBinders.length; binderIdx++) {
|
||||
var binder = pv.elementBinders[binderIdx];
|
||||
if (isPresent(binder.nestedProtoView)) {
|
||||
target.push(elementOffset + binderIdx);
|
||||
calcHostElementIndicesByViewIndex(binder.nestedProtoView,
|
||||
elementOffset + pv.elementBinders.length, target);
|
||||
elementOffset += countNestedElementBinders(binder.nestedProtoView);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
function countNestedProtoViews(pv: AppProtoView, target: number[] = null): number[] {
|
||||
if (isBlank(target)) {
|
||||
target = [];
|
||||
}
|
||||
target.push(null);
|
||||
var resultIndex = target.length - 1;
|
||||
var count = 0;
|
||||
for (var binderIdx = 0; binderIdx < pv.elementBinders.length; binderIdx++) {
|
||||
var binder = pv.elementBinders[binderIdx];
|
||||
if (isPresent(binder.nestedProtoView)) {
|
||||
var nextResultIndex = target.length;
|
||||
countNestedProtoViews(binder.nestedProtoView, target);
|
||||
count += target[nextResultIndex] + 1;
|
||||
}
|
||||
}
|
||||
target[resultIndex] = count;
|
||||
return target;
|
||||
return new ElementBinder(0, null, 0, createProtoElInjector(), componentBinding, nestedProtoView);
|
||||
}
|
||||
|
||||
function _createProtoView(type: ViewType, binders: ElementBinder[] = null) {
|
||||
if (isBlank(binders)) {
|
||||
binders = [];
|
||||
}
|
||||
var protoChangeDetector = <any>new SpyProtoChangeDetector();
|
||||
protoChangeDetector.spy('instantiate').andReturn(new SpyChangeDetector());
|
||||
var res = new AppProtoView(type, null, null, protoChangeDetector, null, null, 0, null);
|
||||
res.elementBinders = binders;
|
||||
var mappedElementIndices = ListWrapper.createFixedSize(countNestedElementBinders(res));
|
||||
var res = new AppProtoView([], type, true, (_) => new SpyChangeDetector(), new Map<string, any>(),
|
||||
null);
|
||||
var mergedElementCount = 0;
|
||||
var mergedEmbeddedViewCount = 0;
|
||||
var mergedViewCount = 1;
|
||||
for (var i = 0; i < binders.length; i++) {
|
||||
var binder = binders[i];
|
||||
mappedElementIndices[i] = i;
|
||||
binder.protoElementInjector.index = i;
|
||||
mergedElementCount++;
|
||||
var nestedPv = binder.nestedProtoView;
|
||||
if (isPresent(nestedPv)) {
|
||||
mergedElementCount += nestedPv.mergeInfo.elementCount;
|
||||
mergedEmbeddedViewCount += nestedPv.mergeInfo.embeddedViewCount;
|
||||
mergedViewCount += nestedPv.mergeInfo.viewCount;
|
||||
if (nestedPv.type === ViewType.EMBEDDED) {
|
||||
mergedEmbeddedViewCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
var hostElementIndicesByViewIndex = calcHostElementIndicesByViewIndex(res);
|
||||
if (type === ViewType.EMBEDDED || type === ViewType.HOST) {
|
||||
res.mergeMapping = new AppProtoViewMergeMapping(
|
||||
new RenderProtoViewMergeMapping(null, hostElementIndicesByViewIndex.length,
|
||||
mappedElementIndices, mappedElementIndices.length, [],
|
||||
hostElementIndicesByViewIndex, countNestedProtoViews(res)));
|
||||
}
|
||||
var mergeInfo =
|
||||
new AppProtoViewMergeInfo(mergedEmbeddedViewCount, mergedElementCount, mergedViewCount);
|
||||
res.init(null, binders, 0, mergeInfo, new Map<string, number>());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,12 +24,10 @@ export function main() {
|
||||
|
||||
function createViewPool({capacity}): AppViewPool { return new AppViewPool(capacity); }
|
||||
|
||||
function createProtoView() {
|
||||
return new AppProtoView(null, null, null, null, null, null, null, null);
|
||||
}
|
||||
function createProtoView() { return new AppProtoView(null, null, null, null, null, null); }
|
||||
|
||||
function createView(pv) {
|
||||
return new AppView(null, pv, null, null, null, null, new Map<string, any>(), null, null);
|
||||
return new AppView(null, pv, null, null, null, new Map<string, any>(), null, null, null);
|
||||
}
|
||||
|
||||
it('should support multiple AppProtoViews', () => {
|
||||
|
||||
@@ -51,7 +51,7 @@ class MessageDir {
|
||||
template: `<div class="child" message="child">
|
||||
<span class="childnested" message="nestedchild">Child</span>
|
||||
</div>
|
||||
<span class="child">{{childBinding}}</span>`,
|
||||
<span class="child" [inner-html]="childBinding"></span>`,
|
||||
directives: [MessageDir]
|
||||
})
|
||||
@Injectable()
|
||||
@@ -66,7 +66,7 @@ class ChildComp {
|
||||
template: `<div class="parent" message="parent">
|
||||
<span class="parentnested" message="nestedparent">Parent</span>
|
||||
</div>
|
||||
<span class="parent">{{parentBinding}}</span>
|
||||
<span class="parent" [inner-html]="parentBinding"></span>
|
||||
<child-comp class="child-comp-class"></child-comp>`,
|
||||
directives: [ChildComp, MessageDir]
|
||||
})
|
||||
@@ -107,9 +107,9 @@ class EventsComp {
|
||||
|
||||
@Component({selector: 'using-for', viewBindings: [Logger]})
|
||||
@View({
|
||||
template: `<span *ng-for="#thing of stuff">{{thing}}</span>
|
||||
template: `<span *ng-for="#thing of stuff" [inner-html]="thing"></span>
|
||||
<ul message="list">
|
||||
<li *ng-for="#item of stuff">{{item}}</li>
|
||||
<li *ng-for="#item of stuff" [inner-html]="item"></li>
|
||||
</ul>`,
|
||||
directives: [NgFor, MessageDir]
|
||||
})
|
||||
|
||||
@@ -41,7 +41,7 @@ export function main() {
|
||||
rootTC.detectChanges();
|
||||
rootTC.debugElement.componentInstance.items = [['1']];
|
||||
|
||||
detectChangesAndCheck(rootTC, 'ng-binding 1', 1);
|
||||
detectChangesAndCheck(rootTC, '1', 1);
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -58,7 +58,7 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
@@ -71,7 +71,7 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo-bar fooBar');
|
||||
detectChangesAndCheck(rootTC, 'foo-bar fooBar');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
@@ -83,10 +83,10 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
rootTC.debugElement.componentInstance.condition = false;
|
||||
detectChangesAndCheck(rootTC, 'ng-binding bar');
|
||||
detectChangesAndCheck(rootTC, 'bar');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -99,16 +99,16 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar');
|
||||
detectChangesAndCheck(rootTC, 'foo bar');
|
||||
|
||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'baz', true);
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar baz');
|
||||
detectChangesAndCheck(rootTC, 'foo bar baz');
|
||||
|
||||
StringMapWrapper.delete(rootTC.debugElement.componentInstance.objExpr, 'bar');
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo baz');
|
||||
detectChangesAndCheck(rootTC, 'foo baz');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -121,13 +121,13 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
rootTC.debugElement.componentInstance.objExpr = {foo: true, bar: true};
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar');
|
||||
detectChangesAndCheck(rootTC, 'foo bar');
|
||||
|
||||
rootTC.debugElement.componentInstance.objExpr = {baz: true};
|
||||
detectChangesAndCheck(rootTC, 'ng-binding baz');
|
||||
detectChangesAndCheck(rootTC, 'baz');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -140,13 +140,13 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
rootTC.debugElement.componentInstance.objExpr = null;
|
||||
detectChangesAndCheck(rootTC, 'ng-binding');
|
||||
detectChangesAndCheck(rootTC, '');
|
||||
|
||||
rootTC.debugElement.componentInstance.objExpr = {'foo': false, 'bar': true};
|
||||
detectChangesAndCheck(rootTC, 'ng-binding bar');
|
||||
detectChangesAndCheck(rootTC, 'bar');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -162,7 +162,7 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar foo-bar fooBar');
|
||||
detectChangesAndCheck(rootTC, 'foo bar foo-bar fooBar');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
@@ -175,16 +175,16 @@ export function main() {
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
var arrExpr: string[] = rootTC.debugElement.componentInstance.arrExpr;
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
arrExpr.push('bar');
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar');
|
||||
detectChangesAndCheck(rootTC, 'foo bar');
|
||||
|
||||
arrExpr[1] = 'baz';
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo baz');
|
||||
detectChangesAndCheck(rootTC, 'foo baz');
|
||||
|
||||
ListWrapper.remove(rootTC.debugElement.componentInstance.arrExpr, 'baz');
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -197,10 +197,10 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
rootTC.debugElement.componentInstance.arrExpr = ['bar'];
|
||||
detectChangesAndCheck(rootTC, 'ng-binding bar');
|
||||
detectChangesAndCheck(rootTC, 'bar');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -213,10 +213,10 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'foo ng-binding');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
rootTC.debugElement.componentInstance.arrExpr = ['bar'];
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar');
|
||||
detectChangesAndCheck(rootTC, 'foo bar');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -231,7 +231,7 @@ export function main() {
|
||||
.then((rootTC) => {
|
||||
|
||||
rootTC.debugElement.componentInstance.arrExpr = ['', ' '];
|
||||
detectChangesAndCheck(rootTC, 'foo ng-binding');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -246,7 +246,7 @@ export function main() {
|
||||
.then((rootTC) => {
|
||||
|
||||
rootTC.debugElement.componentInstance.arrExpr = [' bar '];
|
||||
detectChangesAndCheck(rootTC, 'foo ng-binding bar');
|
||||
detectChangesAndCheck(rootTC, 'foo bar');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -262,7 +262,7 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar foo-bar fooBar');
|
||||
detectChangesAndCheck(rootTC, 'foo bar foo-bar fooBar');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
@@ -274,14 +274,14 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
rootTC.debugElement.componentInstance.strExpr = 'foo bar';
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo bar');
|
||||
detectChangesAndCheck(rootTC, 'foo bar');
|
||||
|
||||
|
||||
rootTC.debugElement.componentInstance.strExpr = 'baz';
|
||||
detectChangesAndCheck(rootTC, 'ng-binding baz');
|
||||
detectChangesAndCheck(rootTC, 'baz');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -294,10 +294,10 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
rootTC.debugElement.componentInstance.strExpr = null;
|
||||
detectChangesAndCheck(rootTC, 'ng-binding');
|
||||
detectChangesAndCheck(rootTC, '');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -310,10 +310,10 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'foo ng-binding');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
rootTC.debugElement.componentInstance.strExpr = null;
|
||||
detectChangesAndCheck(rootTC, 'ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -327,7 +327,7 @@ export function main() {
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
rootTC.debugElement.componentInstance.strExpr = '';
|
||||
detectChangesAndCheck(rootTC, 'foo ng-binding');
|
||||
detectChangesAndCheck(rootTC, 'foo');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -345,13 +345,13 @@ export function main() {
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
||||
detectChangesAndCheck(rootTC, 'init foo ng-binding bar');
|
||||
detectChangesAndCheck(rootTC, 'init foo bar');
|
||||
|
||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'foo', false);
|
||||
detectChangesAndCheck(rootTC, 'init ng-binding bar');
|
||||
detectChangesAndCheck(rootTC, 'init bar');
|
||||
|
||||
rootTC.debugElement.componentInstance.objExpr = null;
|
||||
detectChangesAndCheck(rootTC, 'init ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'init foo');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -365,13 +365,13 @@ export function main() {
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
||||
detectChangesAndCheck(rootTC, `{{'init foo'}} ng-binding init foo bar`);
|
||||
detectChangesAndCheck(rootTC, `init foo bar`);
|
||||
|
||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'foo', false);
|
||||
detectChangesAndCheck(rootTC, `{{'init foo'}} ng-binding init bar`);
|
||||
detectChangesAndCheck(rootTC, `init bar`);
|
||||
|
||||
rootTC.debugElement.componentInstance.objExpr = null;
|
||||
detectChangesAndCheck(rootTC, `{{'init foo'}} ng-binding init foo`);
|
||||
detectChangesAndCheck(rootTC, `init foo`);
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -385,13 +385,13 @@ export function main() {
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
||||
detectChangesAndCheck(rootTC, `init ng-binding foo bar`);
|
||||
detectChangesAndCheck(rootTC, `init foo bar`);
|
||||
|
||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'foo', false);
|
||||
detectChangesAndCheck(rootTC, `init ng-binding bar`);
|
||||
detectChangesAndCheck(rootTC, `init bar`);
|
||||
|
||||
rootTC.debugElement.componentInstance.objExpr = null;
|
||||
detectChangesAndCheck(rootTC, `init ng-binding foo`);
|
||||
detectChangesAndCheck(rootTC, `init foo`);
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -405,16 +405,16 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'init foo ng-binding baz');
|
||||
detectChangesAndCheck(rootTC, 'init foo baz');
|
||||
|
||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
||||
detectChangesAndCheck(rootTC, 'init foo ng-binding baz bar');
|
||||
detectChangesAndCheck(rootTC, 'init foo baz bar');
|
||||
|
||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'foo', false);
|
||||
detectChangesAndCheck(rootTC, 'init ng-binding baz bar');
|
||||
detectChangesAndCheck(rootTC, 'init baz bar');
|
||||
|
||||
rootTC.debugElement.componentInstance.condition = false;
|
||||
detectChangesAndCheck(rootTC, 'init ng-binding bar');
|
||||
detectChangesAndCheck(rootTC, 'init bar');
|
||||
|
||||
async.done();
|
||||
});
|
||||
@@ -427,16 +427,16 @@ export function main() {
|
||||
tcb.overrideTemplate(TestComponent, template)
|
||||
.createAsync(TestComponent)
|
||||
.then((rootTC) => {
|
||||
detectChangesAndCheck(rootTC, 'init ng-binding foo');
|
||||
detectChangesAndCheck(rootTC, 'init foo');
|
||||
|
||||
StringMapWrapper.set(rootTC.debugElement.componentInstance.objExpr, 'bar', true);
|
||||
detectChangesAndCheck(rootTC, 'init ng-binding foo bar');
|
||||
detectChangesAndCheck(rootTC, 'init foo bar');
|
||||
|
||||
rootTC.debugElement.componentInstance.strExpr = 'baz';
|
||||
detectChangesAndCheck(rootTC, 'init ng-binding bar baz foo');
|
||||
detectChangesAndCheck(rootTC, 'init bar baz foo');
|
||||
|
||||
rootTC.debugElement.componentInstance.objExpr = null;
|
||||
detectChangesAndCheck(rootTC, 'init ng-binding baz');
|
||||
detectChangesAndCheck(rootTC, 'init baz');
|
||||
|
||||
async.done();
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
xit,
|
||||
} from 'angular2/test_lib';
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {Component, Directive, NgNonBindable, View} from 'angular2/core';
|
||||
import {Component, Directive, View} from 'angular2/core';
|
||||
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
||||
|
||||
export function main() {
|
||||
@@ -66,7 +66,7 @@ class TestDirective {
|
||||
}
|
||||
|
||||
@Component({selector: 'test-cmp'})
|
||||
@View({directives: [NgNonBindable, TestDirective]})
|
||||
@View({directives: [TestDirective]})
|
||||
class TestComponent {
|
||||
text: string;
|
||||
constructor() { this.text = 'foo'; }
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
Validators,
|
||||
} from 'angular2/core';
|
||||
import {By} from 'angular2/src/core/debug';
|
||||
import {ListWrapper} from 'angular2/src/core/facade/collection';
|
||||
|
||||
export function main() {
|
||||
describe("integration tests", () => {
|
||||
@@ -660,21 +661,18 @@ export function main() {
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.debugElement.query(By.css("input")).nativeElement;
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(['ng-binding', 'ng-invalid', 'ng-pristine', 'ng-untouched']);
|
||||
expect(sortedClassList(input)).toEqual(['ng-invalid', 'ng-pristine', 'ng-untouched']);
|
||||
|
||||
dispatchEvent(input, "blur");
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-touched"]);
|
||||
expect(sortedClassList(input)).toEqual(["ng-invalid", "ng-pristine", "ng-touched"]);
|
||||
|
||||
input.value = "updatedValue";
|
||||
dispatchEvent(input, "change");
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-touched", "ng-dirty", "ng-valid"]);
|
||||
expect(sortedClassList(input)).toEqual(["ng-dirty", "ng-touched", "ng-valid"]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
@@ -690,21 +688,18 @@ export function main() {
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.debugElement.query(By.css("input")).nativeElement;
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-untouched"]);
|
||||
expect(sortedClassList(input)).toEqual(["ng-invalid", "ng-pristine", "ng-untouched"]);
|
||||
|
||||
dispatchEvent(input, "blur");
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-touched"]);
|
||||
expect(sortedClassList(input)).toEqual(["ng-invalid", "ng-pristine", "ng-touched"]);
|
||||
|
||||
input.value = "updatedValue";
|
||||
dispatchEvent(input, "change");
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-touched", "ng-dirty", "ng-valid"]);
|
||||
expect(sortedClassList(input)).toEqual(["ng-dirty", "ng-touched", "ng-valid"]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
@@ -718,21 +713,18 @@ export function main() {
|
||||
rootTC.detectChanges();
|
||||
|
||||
var input = rootTC.debugElement.query(By.css("input")).nativeElement;
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-untouched"]);
|
||||
expect(sortedClassList(input)).toEqual(["ng-invalid", "ng-pristine", "ng-untouched"]);
|
||||
|
||||
dispatchEvent(input, "blur");
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-invalid", "ng-pristine", "ng-touched"]);
|
||||
expect(sortedClassList(input)).toEqual(["ng-invalid", "ng-pristine", "ng-touched"]);
|
||||
|
||||
input.value = "updatedValue";
|
||||
dispatchEvent(input, "change");
|
||||
rootTC.detectChanges();
|
||||
|
||||
expect(DOM.classList(input))
|
||||
.toEqual(["ng-binding", "ng-touched", "ng-dirty", "ng-valid"]);
|
||||
expect(sortedClassList(input)).toEqual(["ng-dirty", "ng-touched", "ng-valid"]);
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
@@ -845,3 +837,9 @@ class MyComp {
|
||||
name: string;
|
||||
data: any;
|
||||
}
|
||||
|
||||
function sortedClassList(el) {
|
||||
var l = DOM.classList(el);
|
||||
ListWrapper.sort(l);
|
||||
return l;
|
||||
}
|
||||
@@ -34,27 +34,29 @@ export function main() {
|
||||
() => { injector = Injector.resolveAndCreate([bind('dep').toValue('dependency')]); });
|
||||
|
||||
it('should instantiate a pipe', () => {
|
||||
var proto = new ProtoPipes([PipeBinding.createFromType(PipeA, new Pipe({name: 'a'}))]);
|
||||
var proto =
|
||||
ProtoPipes.fromBindings([PipeBinding.createFromType(PipeA, new Pipe({name: 'a'}))]);
|
||||
var pipes = new Pipes(proto, injector);
|
||||
|
||||
expect(pipes.get("a").pipe).toBeAnInstanceOf(PipeA);
|
||||
});
|
||||
|
||||
it('should throw when no pipe found', () => {
|
||||
var proto = new ProtoPipes([]);
|
||||
var proto = ProtoPipes.fromBindings([]);
|
||||
var pipes = new Pipes(proto, injector);
|
||||
expect(() => pipes.get("invalid")).toThrowErrorWith("Cannot find pipe 'invalid'");
|
||||
});
|
||||
|
||||
it('should inject dependencies from the provided injector', () => {
|
||||
var proto = new ProtoPipes([PipeBinding.createFromType(PipeB, new Pipe({name: 'b'}))]);
|
||||
var proto =
|
||||
ProtoPipes.fromBindings([PipeBinding.createFromType(PipeB, new Pipe({name: 'b'}))]);
|
||||
var pipes = new Pipes(proto, injector);
|
||||
expect((<any>pipes.get("b").pipe).dep).toEqual("dependency");
|
||||
});
|
||||
|
||||
it('should cache pure pipes', () => {
|
||||
var proto =
|
||||
new ProtoPipes([PipeBinding.createFromType(PipeA, new Pipe({name: 'a', pure: true}))]);
|
||||
var proto = ProtoPipes.fromBindings(
|
||||
[PipeBinding.createFromType(PipeA, new Pipe({name: 'a', pure: true}))]);
|
||||
var pipes = new Pipes(proto, injector);
|
||||
|
||||
expect(pipes.get("a").pure).toEqual(true);
|
||||
@@ -62,8 +64,8 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should NOT cache impure pipes', () => {
|
||||
var proto =
|
||||
new ProtoPipes([PipeBinding.createFromType(PipeA, new Pipe({name: 'a', pure: false}))]);
|
||||
var proto = ProtoPipes.fromBindings(
|
||||
[PipeBinding.createFromType(PipeA, new Pipe({name: 'a', pure: false}))]);
|
||||
var pipes = new Pipes(proto, injector);
|
||||
|
||||
expect(pipes.get("a").pure).toEqual(false);
|
||||
|
||||
@@ -248,15 +248,11 @@ export function main() {
|
||||
});
|
||||
|
||||
if (IS_DART) {
|
||||
describe("moduleId", () => {
|
||||
it("should return the moduleId for a type", () => {
|
||||
expect(reflector.moduleId(TestObjWith00Args))
|
||||
.toEqual('base/dist/dart/angular2/test/core/reflection/reflector_spec');
|
||||
});
|
||||
|
||||
it("should return an empty array otherwise", () => {
|
||||
var p = reflector.interfaces(ClassWithDecorators);
|
||||
expect(p).toEqual([]);
|
||||
describe("importUri", () => {
|
||||
it("should return the importUri for a type", () => {
|
||||
expect(reflector.importUri(TestObjWith00Args)
|
||||
.endsWith('base/dist/dart/angular2/test/core/reflection/reflector_spec.dart'))
|
||||
.toBe(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,266 +13,22 @@ import {
|
||||
SpyObject,
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {MapWrapper} from 'angular2/src/core/facade/collection';
|
||||
import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
// import {MapWrapper} from 'angular2/src/core/facade/collection';
|
||||
// import {DOM} from 'angular2/src/core/dom/dom_adapter';
|
||||
|
||||
import {DomTestbed, TestRootView, elRef} from './dom_testbed';
|
||||
// import {DomTestbed, TestRootView, elRef} from './dom_testbed';
|
||||
|
||||
import {
|
||||
ViewDefinition,
|
||||
RenderDirectiveMetadata,
|
||||
RenderViewRef,
|
||||
ViewEncapsulation
|
||||
} from 'angular2/src/core/render/api';
|
||||
// import {
|
||||
// ViewDefinition,
|
||||
// RenderDirectiveMetadata,
|
||||
// RenderViewRef,
|
||||
// ViewEncapsulation
|
||||
// } from 'angular2/src/core/render/api';
|
||||
|
||||
export function main() {
|
||||
describe('DomRenderer integration', () => {
|
||||
beforeEachBindings(() => [DomTestbed]);
|
||||
|
||||
it('should create and destroy root host views while using the given elements in place',
|
||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compiler.compileHost(someComponent)
|
||||
.then((hostProtoViewDto) => {
|
||||
var view = new TestRootView(
|
||||
tb.renderer.createRootHostView(hostProtoViewDto.render, 0, '#root'));
|
||||
expect(tb.rootEl.parentNode).toBeTruthy();
|
||||
expect(view.hostElement).toEqual(tb.rootEl);
|
||||
|
||||
tb.renderer.detachFragment(view.fragments[0]);
|
||||
tb.renderer.destroyView(view.viewRef);
|
||||
expect(tb.rootEl.parentNode).toBeFalsy();
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should update text nodes',
|
||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compileAndMerge(
|
||||
someComponent,
|
||||
[
|
||||
new ViewDefinition(
|
||||
{componentId: 'someComponent', template: '{{a}}', directives: []})
|
||||
])
|
||||
.then((protoViewMergeMappings) => {
|
||||
var rootView = tb.createView(protoViewMergeMappings);
|
||||
|
||||
tb.renderer.setText(rootView.viewRef, 0, 'hello');
|
||||
expect(rootView.hostElement).toHaveText('hello');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
it('should update any element property/attributes/class/style independent of the compilation on the root element and other elements',
|
||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compileAndMerge(someComponent,
|
||||
[
|
||||
new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '<input [title]="y" style="position:absolute">',
|
||||
directives: []
|
||||
})
|
||||
])
|
||||
.then((protoViewMergeMappings) => {
|
||||
|
||||
var checkSetters = (elr, el) => {
|
||||
tb.renderer.setElementProperty(elr, 'tabIndex', 1);
|
||||
expect((<HTMLInputElement>el).tabIndex).toEqual(1);
|
||||
|
||||
tb.renderer.setElementClass(elr, 'a', true);
|
||||
expect(DOM.hasClass(el, 'a')).toBe(true);
|
||||
tb.renderer.setElementClass(elr, 'a', false);
|
||||
expect(DOM.hasClass(el, 'a')).toBe(false);
|
||||
|
||||
tb.renderer.setElementStyle(elr, 'width', '10px');
|
||||
expect(DOM.getStyle(el, 'width')).toEqual('10px');
|
||||
tb.renderer.setElementStyle(elr, 'width', null);
|
||||
expect(DOM.getStyle(el, 'width')).toEqual('');
|
||||
|
||||
tb.renderer.setElementAttribute(elr, 'someAttr', 'someValue');
|
||||
expect(DOM.getAttribute(el, 'some-attr')).toEqual('someValue');
|
||||
};
|
||||
|
||||
var rootView = tb.createView(protoViewMergeMappings);
|
||||
// root element
|
||||
checkSetters(elRef(rootView.viewRef, 0), rootView.hostElement);
|
||||
// nested elements
|
||||
checkSetters(elRef(rootView.viewRef, 1), DOM.firstChild(rootView.hostElement));
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
if (DOM.supportsDOMEvents()) {
|
||||
it('should call actions on the element independent of the compilation',
|
||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compileAndMerge(someComponent,
|
||||
[
|
||||
new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '<input [title]="y"></input>',
|
||||
directives: []
|
||||
})
|
||||
])
|
||||
.then((protoViewMergeMappings) => {
|
||||
var rootView = tb.createView(protoViewMergeMappings);
|
||||
|
||||
tb.renderer.invokeElementMethod(elRef(rootView.viewRef, 1), 'setAttribute',
|
||||
['a', 'b']);
|
||||
|
||||
expect(DOM.getAttribute(DOM.childNodes(rootView.hostElement)[0], 'a'))
|
||||
.toEqual('b');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
it('should add and remove fragments',
|
||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compileAndMerge(someComponent,
|
||||
[
|
||||
new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '<template>hello</template>',
|
||||
directives: []
|
||||
})
|
||||
])
|
||||
.then((protoViewMergeMappings) => {
|
||||
var rootView = tb.createView(protoViewMergeMappings);
|
||||
|
||||
var elr = elRef(rootView.viewRef, 1);
|
||||
expect(rootView.hostElement).toHaveText('');
|
||||
var fragment = rootView.fragments[1];
|
||||
tb.renderer.attachFragmentAfterElement(elr, fragment);
|
||||
expect(rootView.hostElement).toHaveText('hello');
|
||||
tb.renderer.detachFragment(fragment);
|
||||
expect(rootView.hostElement).toHaveText('');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should add and remove empty fragments',
|
||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compileAndMerge(someComponent,
|
||||
[
|
||||
new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '<template></template><template></template>',
|
||||
directives: []
|
||||
})
|
||||
])
|
||||
.then((protoViewMergeMappings) => {
|
||||
var rootView = tb.createView(protoViewMergeMappings);
|
||||
|
||||
var elr = elRef(rootView.viewRef, 1);
|
||||
expect(rootView.hostElement).toHaveText('');
|
||||
var fragment = rootView.fragments[1];
|
||||
var fragment2 = rootView.fragments[2];
|
||||
tb.renderer.attachFragmentAfterElement(elr, fragment);
|
||||
tb.renderer.attachFragmentAfterFragment(fragment, fragment2);
|
||||
tb.renderer.detachFragment(fragment);
|
||||
tb.renderer.detachFragment(fragment2);
|
||||
expect(rootView.hostElement).toHaveText('');
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should handle events', inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compileAndMerge(someComponent,
|
||||
[
|
||||
new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '<input (change)="doSomething()">',
|
||||
directives: []
|
||||
})
|
||||
])
|
||||
.then((protoViewMergeMappings) => {
|
||||
var rootView = tb.createView(protoViewMergeMappings);
|
||||
|
||||
tb.triggerEvent(elRef(rootView.viewRef, 1), 'change');
|
||||
var eventEntry = rootView.events[0];
|
||||
// bound element index
|
||||
expect(eventEntry[0]).toEqual(1);
|
||||
// event type
|
||||
expect(eventEntry[1]).toEqual('change');
|
||||
// actual event
|
||||
expect((<Map<any, any>>eventEntry[2]).get('$event').type).toEqual('change');
|
||||
async.done();
|
||||
});
|
||||
|
||||
}));
|
||||
|
||||
if (DOM.supportsNativeShadowDOM()) {
|
||||
describe('native shadow dom support', () => {
|
||||
it('should put the template into a shadow root',
|
||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compileAndMerge(someComponent,
|
||||
[
|
||||
new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: 'hello',
|
||||
directives: [],
|
||||
encapsulation: ViewEncapsulation.Native
|
||||
})
|
||||
])
|
||||
.then((protoViewMergeMappings) => {
|
||||
var rootView = tb.createView(protoViewMergeMappings);
|
||||
expect(DOM.getShadowRoot(rootView.hostElement)).toHaveText('hello');
|
||||
async.done();
|
||||
});
|
||||
|
||||
}));
|
||||
|
||||
it('should add styles from non native components to shadow roots while the view is not destroyed',
|
||||
inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
|
||||
tb.compileAndMerge(someComponent,
|
||||
[
|
||||
new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '',
|
||||
directives: [],
|
||||
encapsulation: ViewEncapsulation.Native,
|
||||
styles: ['a {};']
|
||||
})
|
||||
])
|
||||
.then((protoViewMergeMappings) => {
|
||||
var rootView = tb.createView(protoViewMergeMappings);
|
||||
tb.compiler.compile(new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '',
|
||||
directives: [],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
styles: ['b {};']
|
||||
}))
|
||||
.then(_ => {
|
||||
expect(DOM.getShadowRoot(rootView.hostElement)).toHaveText('a {};b {};');
|
||||
tb.renderer.destroyView(rootView.viewRef);
|
||||
tb.compiler.compile(new ViewDefinition({
|
||||
componentId: 'someComponent',
|
||||
template: '',
|
||||
directives: [],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
styles: ['c {};']
|
||||
}))
|
||||
.then(_ => {
|
||||
expect(DOM.getShadowRoot(rootView.hostElement))
|
||||
.toHaveText('a {};b {};');
|
||||
async.done();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
it('should work', () => {
|
||||
// TODO
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export var someComponent = RenderDirectiveMetadata.create(
|
||||
{id: 'someComponent', type: RenderDirectiveMetadata.COMPONENT_TYPE, selector: 'some-comp'});
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:angular2/src/core/compiler/directive_resolver.dart';
|
||||
import 'package:angular2/src/core/compiler/view.dart';
|
||||
import 'package:angular2/src/core/compiler/element_ref.dart';
|
||||
import 'package:angular2/src/core/compiler/view_manager.dart';
|
||||
import 'package:angular2/src/core/compiler/proto_view_factory.dart';
|
||||
import 'package:angular2/src/core/compiler/view_pool.dart';
|
||||
import 'package:angular2/src/core/compiler/view_listener.dart';
|
||||
import 'package:angular2/src/core/compiler/element_injector.dart';
|
||||
@@ -91,6 +92,11 @@ class SpyAppViewListener extends SpyObject implements AppViewListener {
|
||||
noSuchMethod(m) => super.noSuchMethod(m);
|
||||
}
|
||||
|
||||
@proxy
|
||||
class SpyProtoViewFactory extends SpyObject implements ProtoViewFactory {
|
||||
noSuchMethod(m) => super.noSuchMethod(m);
|
||||
}
|
||||
|
||||
@proxy
|
||||
class SpyProtoElementInjector extends SpyObject implements ProtoElementInjector {
|
||||
noSuchMethod(m) => super.noSuchMethod(m);
|
||||
|
||||
@@ -14,6 +14,7 @@ import {ElementRef} from 'angular2/src/core/compiler/element_ref';
|
||||
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||
import {AppViewPool} from 'angular2/src/core/compiler/view_pool';
|
||||
import {AppViewListener} from 'angular2/src/core/compiler/view_listener';
|
||||
import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
import {DomAdapter} from 'angular2/src/core/dom/dom_adapter';
|
||||
import {ClientMessageBroker} from 'angular2/src/web_workers/shared/client_message_broker';
|
||||
import {XHR} from 'angular2/src/core/render/xhr';
|
||||
@@ -76,6 +77,10 @@ export class SpyAppViewListener extends SpyObject {
|
||||
constructor() { super(AppViewListener); }
|
||||
}
|
||||
|
||||
export class SpyProtoViewFactory extends SpyObject {
|
||||
constructor() { super(ProtoViewFactory); }
|
||||
}
|
||||
|
||||
export class SpyProtoElementInjector extends SpyObject {
|
||||
constructor() { super(ProtoElementInjector); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user