refactor(render): ts’ify tests

This commit is contained in:
Tobias Bosch 2015-05-26 09:25:39 -07:00
parent d773b6a00a
commit 1dc8ba6920
30 changed files with 1690 additions and 1801 deletions

View File

@ -1,6 +1,6 @@
/*
* Runs compiler tests using in-browser DOM adapter.
*/
/*
* Runs compiler tests using in-browser DOM adapter.
*/
import {runCompilerCommonTests} from './compiler_common_tests';

View File

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

View File

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

View File

@ -9,12 +9,13 @@ import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control';
import {ViewDefinition, DirectiveMetadata} from 'angular2/src/render/api';
import {Lexer, Parser} from 'angular2/change_detection';
import {ElementBinderBuilder} from 'angular2/src/render/dom/view/proto_view_builder';
export function main() {
describe('DirectiveParser', () => {
var parser, annotatedDirectives;
beforeEach( () => {
beforeEach(() => {
annotatedDirectives = [
someComponent,
someComponent2,
@ -35,20 +36,21 @@ export function main() {
if (isBlank(directives)) directives = annotatedDirectives;
return new CompilePipeline([
new MockStep( (parent, current, control) => {
if (isPresent(propertyBindings)) {
StringMapWrapper.forEach(propertyBindings, (ast, name) => {
current.bindElement().bindProperty(name, ast);
});
}
}),
new MockStep((parent, current, control) =>
{
if (isPresent(propertyBindings)) {
StringMapWrapper.forEach(propertyBindings, (ast, name) => {
current.bindElement().bindProperty(name, ast);
});
}
}),
new DirectiveParser(parser, directives)
]);
}
function process(el, propertyBindings = null, directives = null) {
function process(el, propertyBindings = null, directives = null): List<ElementBinderBuilder> {
var pipeline = createPipeline(propertyBindings, directives);
return ListWrapper.map(pipeline.process(el), (ce) => ce.inheritedElementBinder );
return ListWrapper.map(pipeline.process(el), (ce) => ce.inheritedElementBinder);
}
it('should not add directives if they are not used', () => {
@ -58,16 +60,14 @@ export function main() {
it('should detect directives in attributes', () => {
var results = process(el('<div some-decor></div>'));
expect(results[0].directives[0].directiveIndex).toBe(
annotatedDirectives.indexOf(someDirective)
);
expect(results[0].directives[0].directiveIndex)
.toBe(annotatedDirectives.indexOf(someDirective));
});
it('should detect directives with multiple attributes', () => {
var results = process(el('<input type=text control=one></input>'));
expect(results[0].directives[0].directiveIndex).toBe(
annotatedDirectives.indexOf(decoratorWithMultipleAttrs)
);
expect(results[0].directives[0].directiveIndex)
.toBe(annotatedDirectives.indexOf(decoratorWithMultipleAttrs));
});
it('should compile children by default', () => {
@ -81,36 +81,26 @@ export function main() {
});
it('should bind directive properties from bound properties', () => {
var results = process(
el('<div some-decor-props></div>'),
{
'elProp': parser.parseBinding('someExpr', '')
}
);
var results = process(el('<div some-decor-props></div>'),
{'elProp': parser.parseBinding('someExpr', '')});
var directiveBinding = results[0].directives[0];
expect(MapWrapper.get(directiveBinding.propertyBindings, 'dirProp').source)
.toEqual('someExpr');
.toEqual('someExpr');
});
it('should bind directive properties with pipes', () => {
var results = process(
el('<div some-decor-props></div>'),
{
'elProp': parser.parseBinding('someExpr', '')
}
);
var results = process(el('<div some-decor-props></div>'),
{'elProp': parser.parseBinding('someExpr', '')});
var directiveBinding = results[0].directives[0];
var pipedProp = MapWrapper.get(directiveBinding.propertyBindings, 'doubleProp');
var simpleProp = MapWrapper.get(directiveBinding.propertyBindings, 'dirProp');
var pipedProp = <any>MapWrapper.get(directiveBinding.propertyBindings, 'doubleProp');
var simpleProp = <any>MapWrapper.get(directiveBinding.propertyBindings, 'dirProp');
expect(pipedProp.ast.name).toEqual('double');
expect(pipedProp.ast.exp).toEqual(simpleProp.ast);
expect(simpleProp.source).toEqual('someExpr');
});
it('should bind directive properties from attribute values', () => {
var results = process(
el('<div some-decor-props el-prop="someValue"></div>')
);
var results = process(el('<div some-decor-props el-prop="someValue"></div>'));
var directiveBinding = results[0].directives[0];
var simpleProp = MapWrapper.get(directiveBinding.propertyBindings, 'dirProp');
expect(simpleProp.source).toEqual('someValue');
@ -160,9 +150,7 @@ export function main() {
});
it('should bind directive events', () => {
var results = process(
el('<div some-decor-events></div>')
);
var results = process(el('<div some-decor-events></div>'));
var directiveBinding = results[0].directives[0];
expect(directiveBinding.eventBindings.length).toEqual(1);
var eventBinding = directiveBinding.eventBindings[0];
@ -171,9 +159,7 @@ export function main() {
});
it('should bind directive global events', () => {
var results = process(
el('<div some-decor-globalevents></div>')
);
var results = process(el('<div some-decor-globalevents></div>'));
var directiveBinding = results[0].directives[0];
expect(directiveBinding.eventBindings.length).toEqual(1);
var eventBinding = directiveBinding.eventBindings[0];
@ -182,83 +168,61 @@ export function main() {
});
it('should bind directive host actions', () => {
var results = process(
el('<div some-decor-host-actions></div>')
);
var results = process(el('<div some-decor-host-actions></div>'));
var directiveBinding = results[0].directives[0];
expect(directiveBinding.hostActions[0].actionName).toEqual('focus');
});
//TODO: assertions should be enabled when running tests: https://github.com/angular/angular/issues/1340
// TODO: assertions should be enabled when running tests:
// https://github.com/angular/angular/issues/1340
describe('component directives', () => {
it('should save the component id', () => {
var results = process(
el('<some-comp></some-comp>')
);
var results = process(el('<some-comp></some-comp>'));
expect(results[0].componentId).toEqual('someComponent');
});
it('should throw when the provided selector is not an element selector', () => {
expect( () => {
createPipeline(null, [componentWithNonElementSelector]);
}).toThrowError(`Component 'componentWithNonElementSelector' can only have an element selector, but had '[attr]'`);
expect(() => { createPipeline(null, [componentWithNonElementSelector]); })
.toThrowError(
`Component 'componentWithNonElementSelector' can only have an element selector, but had '[attr]'`);
});
it('should not allow multiple component directives on the same element', () => {
expect( () => {
process(
el('<some-comp></some-comp>'),
null,
[someComponent, someComponentDup]
);
}).toThrowError(new RegExp('Only one component directive is allowed per element' ));
expect(() => {
process(el('<some-comp></some-comp>'), null, [someComponent, someComponentDup]);
}).toThrowError(new RegExp('Only one component directive is allowed per element'));
});
it('should sort the directives and store the component as the first directive', () => {
var results = process(
el('<some-comp some-decor></some-comp>')
);
expect(annotatedDirectives[results[0].directives[0].directiveIndex].id).toEqual('someComponent');
expect(annotatedDirectives[results[0].directives[1].directiveIndex].id).toEqual('someDirective');
var results = process(el('<some-comp some-decor></some-comp>'));
expect(annotatedDirectives[results[0].directives[0].directiveIndex].id)
.toEqual('someComponent');
expect(annotatedDirectives[results[0].directives[1].directiveIndex].id)
.toEqual('someDirective');
});
});
});
}
@IMPLEMENTS(CompileStep)
class MockStep {
processClosure:Function;
constructor(process) {
this.processClosure = process;
}
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
class MockStep implements CompileStep {
processClosure: Function;
constructor(process) { this.processClosure = process; }
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
this.processClosure(parent, current, control);
}
}
var someComponent = new DirectiveMetadata({
selector: 'some-comp',
id: 'someComponent',
type: DirectiveMetadata.COMPONENT_TYPE
});
var someComponent = new DirectiveMetadata(
{selector: 'some-comp', id: 'someComponent', type: DirectiveMetadata.COMPONENT_TYPE});
var someComponentDup = new DirectiveMetadata({
selector: 'some-comp',
id: 'someComponentDup',
type: DirectiveMetadata.COMPONENT_TYPE
});
var someComponentDup = new DirectiveMetadata(
{selector: 'some-comp', id: 'someComponentDup', type: DirectiveMetadata.COMPONENT_TYPE});
var someComponent2 = new DirectiveMetadata({
selector: 'some-comp2',
id: 'someComponent2',
type: DirectiveMetadata.COMPONENT_TYPE
});
var someComponent2 = new DirectiveMetadata(
{selector: 'some-comp2', id: 'someComponent2', type: DirectiveMetadata.COMPONENT_TYPE});
var someDirective = new DirectiveMetadata({
selector: '[some-decor]',
id: 'someDirective',
type: DirectiveMetadata.DIRECTIVE_TYPE
});
var someDirective = new DirectiveMetadata(
{selector: '[some-decor]', id: 'someDirective', type: DirectiveMetadata.DIRECTIVE_TYPE});
var someDirectiveIgnoringChildren = new DirectiveMetadata({
selector: '[some-decor-ignoring-children]',
@ -275,47 +239,34 @@ var decoratorWithMultipleAttrs = new DirectiveMetadata({
var someDirectiveWithProps = new DirectiveMetadata({
selector: '[some-decor-props]',
properties: MapWrapper.createFromStringMap({
'dirProp': 'elProp',
'doubleProp': 'elProp | double'
}),
properties:
MapWrapper.createFromStringMap({'dirProp': 'elProp', 'doubleProp': 'elProp | double'}),
readAttributes: ['some-attr']
});
var someDirectiveWithHostProperties = new DirectiveMetadata({
selector: '[some-decor-with-host-props]',
hostProperties: MapWrapper.createFromStringMap({
'dirProp': 'hostProperty'
})
hostProperties: MapWrapper.createFromStringMap({'dirProp': 'hostProperty'})
});
var someDirectiveWithHostAttributes = new DirectiveMetadata({
selector: '[some-decor-with-host-attrs]',
hostAttributes: MapWrapper.createFromStringMap({
'attr_name': 'attr_val',
'class': 'foo bar'
})
hostAttributes: MapWrapper.createFromStringMap({'attr_name': 'attr_val', 'class': 'foo bar'})
});
var someDirectiveWithEvents = new DirectiveMetadata({
selector: '[some-decor-events]',
hostListeners: MapWrapper.createFromStringMap({
'click': 'doIt()'
})
hostListeners: MapWrapper.createFromStringMap({'click': 'doIt()'})
});
var someDirectiveWithHostActions = new DirectiveMetadata({
selector: '[some-decor-host-actions]',
hostActions: MapWrapper.createFromStringMap({
'focus': 'focus()'
})
hostActions: MapWrapper.createFromStringMap({'focus': 'focus()'})
});
var someDirectiveWithGlobalEvents = new DirectiveMetadata({
selector: '[some-decor-globalevents]',
hostListeners: MapWrapper.createFromStringMap({
'window:resize': 'doItGlobal()'
})
hostListeners: MapWrapper.createFromStringMap({'window:resize': 'doItGlobal()'})
});
var componentWithNonElementSelector = new DirectiveMetadata({

View File

@ -5,7 +5,7 @@ import {isPresent, NumberWrapper, StringWrapper, IMPLEMENTS} from 'angular2/src/
import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline';
import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step'
import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step';
import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control';
import {ProtoViewBuilder} from 'angular2/src/render/dom/view/proto_view_builder';
@ -25,7 +25,8 @@ export function main() {
});
it('should stop walking the tree when compileChildren is false', () => {
var element = el('<div id="1"><template id="2" ignore-children><span id="3"></span></template></div>');
var element = el(
'<div id="1"><template id="2" ignore-children><span id="3"></span></template></div>');
var step0Log = [];
var pipeline = new CompilePipeline([new IgnoreChildrenStep(), createLoggerStep(step0Log)]);
@ -40,7 +41,8 @@ export function main() {
var element = el('<div><div><span viewroot><span></span></span></div></div>');
var pipeline = new CompilePipeline([new MockStep((parent, current, control) => {
if (isPresent(DOM.getAttribute(current.element, 'viewroot'))) {
current.inheritedProtoView = new ProtoViewBuilder(current.element, ProtoViewDto.EMBEDDED_VIEW_TYPE);
current.inheritedProtoView =
new ProtoViewBuilder(current.element, ProtoViewDto.EMBEDDED_VIEW_TYPE);
}
})]);
var results = pipeline.process(element);
@ -99,10 +101,8 @@ export function main() {
var element = el('<div id="1"><span wrap0="1" id="2"><b id="3"></b></span></div>');
var step0Log = [];
var step1Log = [];
var pipeline = new CompilePipeline([
createWrapperStep('wrap0', step0Log),
createLoggerStep(step1Log)
]);
var pipeline = new CompilePipeline(
[createWrapperStep('wrap0', step0Log), createLoggerStep(step1Log)]);
var result = pipeline.process(element);
expect(step0Log).toEqual(['1', '1<2', '2<3']);
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<2', '2<3']);
@ -110,7 +110,8 @@ export function main() {
});
it('should allow to add a parent by multiple processors to the same element', () => {
var element = el('<div id="1"><span wrap0="1" wrap1="1" id="2"><b id="3"></b></span></div>');
var element =
el('<div id="1"><span wrap0="1" wrap1="1" id="2"><b id="3"></b></span></div>');
var step0Log = [];
var step1Log = [];
var step2Log = [];
@ -127,7 +128,8 @@ export function main() {
});
it('should allow to add a parent by multiple processors to different elements', () => {
var element = el('<div id="1"><span wrap0="1" id="2"><b id="3" wrap1="1"></b></span></div>');
var element =
el('<div id="1"><span wrap0="1" id="2"><b id="3" wrap1="1"></b></span></div>');
var step0Log = [];
var step1Log = [];
var step2Log = [];
@ -147,10 +149,8 @@ export function main() {
var element = el('<div id="1"><span wrap0="2" id="2"><b id="3"></b></span></div>');
var step0Log = [];
var step1Log = [];
var pipeline = new CompilePipeline([
createWrapperStep('wrap0', step0Log),
createLoggerStep(step1Log)
]);
var pipeline = new CompilePipeline(
[createWrapperStep('wrap0', step0Log), createLoggerStep(step1Log)]);
var result = pipeline.process(element);
expect(step0Log).toEqual(['1', '1<2', '2<3']);
expect(step1Log).toEqual(['1', '1<wrap0#0', 'wrap0#0<wrap0#1', 'wrap0#1<2', '2<3']);
@ -165,11 +165,12 @@ export function main() {
var resultLog = [];
var newChild = new CompileElement(el('<div id="3"></div>'));
var pipeline = new CompilePipeline([
new MockStep((parent, current, control) => {
if (StringWrapper.equals(DOM.getAttribute(current.element, 'id'), '1')) {
control.addChild(newChild);
}
}),
new MockStep((parent, current, control) =>
{
if (StringWrapper.equals(DOM.getAttribute(current.element, 'id'), '1')) {
control.addChild(newChild);
}
}),
createLoggerStep(resultLog)
]);
var result = pipeline.process(element);
@ -182,20 +183,16 @@ export function main() {
});
}
@IMPLEMENTS(CompileStep)
class MockStep {
processClosure:Function;
constructor(process) {
this.processClosure = process;
}
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
class MockStep implements CompileStep {
processClosure: Function;
constructor(process) { this.processClosure = process; }
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
this.processClosure(parent, current, control);
}
}
@IMPLEMENTS(CompileStep)
export class IgnoreChildrenStep {
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
export class IgnoreChildrenStep implements CompileStep {
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
var attributeMap = DOM.attributeMap(current.element);
if (MapWrapper.contains(attributeMap, 'ignore-children')) {
current.compileChildren = false;
@ -203,9 +200,8 @@ export class IgnoreChildrenStep {
}
}
@IMPLEMENTS(CompileStep)
class IgnoreCurrentElementStep {
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
class IgnoreCurrentElementStep implements CompileStep {
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
var attributeMap = DOM.attributeMap(current.element);
if (MapWrapper.contains(attributeMap, 'ignore-current')) {
control.ignoreCurrentElement();
@ -222,9 +218,7 @@ function logEntry(log, parent, current) {
}
function createLoggerStep(log) {
return new MockStep((parent, current, control) => {
logEntry(log, parent, current);
});
return new MockStep((parent, current, control) => { logEntry(log, parent, current); });
}
function createWrapperStep(wrapperId, log) {
@ -244,8 +238,6 @@ function createWrapperStep(wrapperId, log) {
function resultIdLog(result) {
var idLog = [];
ListWrapper.forEach(result, (current) => {
logEntry(idLog, null, current);
});
ListWrapper.forEach(result, (current) => { logEntry(idLog, null, current); });
return idLog;
}

View File

@ -7,6 +7,7 @@ import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step';
import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control';
import {Lexer, Parser} from 'angular2/change_detection';
import {ElementBinderBuilder} from 'angular2/src/render/dom/view/proto_view_builder';
var EMPTY_MAP = MapWrapper.create();
@ -14,19 +15,19 @@ export function main() {
describe('PropertyBindingParser', () => {
function createPipeline(hasNestedProtoView = false) {
return new CompilePipeline([
new MockStep((parent, current, control) => {
if (hasNestedProtoView) {
current.bindElement().bindNestedProtoView(el('<template></template>'));
}
}),
new PropertyBindingParser(new Parser(new Lexer()))]);
new MockStep((parent, current, control) =>
{
if (hasNestedProtoView) {
current.bindElement().bindNestedProtoView(el('<template></template>'));
}
}),
new PropertyBindingParser(new Parser(new Lexer()))
]);
}
function process(element, hasNestedProtoView = false) {
return ListWrapper.map(
createPipeline(hasNestedProtoView).process(element),
(compileElement) => compileElement.inheritedElementBinder
);
function process(element, hasNestedProtoView = false): List<ElementBinderBuilder> {
return ListWrapper.map(createPipeline(hasNestedProtoView).process(element),
(compileElement) => compileElement.inheritedElementBinder);
}
it('should detect [] syntax', () => {
@ -44,9 +45,8 @@ export function main() {
expect(MapWrapper.get(results[0].propertyBindings, 'a').source).toEqual('b');
});
it('should detect bind- syntax only if an attribute name starts with bind', () => {
expect(process(el('<div _bind-a="b"></div>'))[0]).toEqual(null);
});
it('should detect bind- syntax only if an attribute name starts with bind',
() => { expect(process(el('<div _bind-a="b"></div>'))[0]).toEqual(null); });
it('should detect interpolation syntax', () => {
var results = process(el('<div a="{{b}}"></div>'));
@ -67,14 +67,17 @@ export function main() {
it('should store variable binding for a template element on the nestedProtoView', () => {
var results = process(el('<template var-george="washington"></p>'), true);
expect(results[0].variableBindings).toEqual(EMPTY_MAP);
expect(MapWrapper.get(results[0].nestedProtoView.variableBindings, 'washington')).toEqual('george');
expect(MapWrapper.get(results[0].nestedProtoView.variableBindings, 'washington'))
.toEqual('george');
});
it('should store variable binding for a non-template element using shorthand syntax on the nestedProtoView', () => {
var results = process(el('<template #george="washington"></template>'), true);
expect(results[0].variableBindings).toEqual(EMPTY_MAP);
expect(MapWrapper.get(results[0].nestedProtoView.variableBindings, 'washington')).toEqual('george');
});
it('should store variable binding for a non-template element using shorthand syntax on the nestedProtoView',
() => {
var results = process(el('<template #george="washington"></template>'), true);
expect(results[0].variableBindings).toEqual(EMPTY_MAP);
expect(MapWrapper.get(results[0].nestedProtoView.variableBindings, 'washington'))
.toEqual('george');
});
it('should store variable binding for a non-template element', () => {
var results = process(el('<p var-george="washington"></p>'));
@ -165,13 +168,10 @@ export function main() {
});
}
@IMPLEMENTS(CompileStep)
class MockStep {
processClosure:Function;
constructor(process) {
this.processClosure = process;
}
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
class MockStep implements CompileStep {
processClosure: Function;
constructor(process) { this.processClosure = process; }
process(parent: CompileElement, current: CompileElement, control: CompileControl) {
this.processClosure(parent, current, control);
}
}

View File

@ -8,9 +8,7 @@ export function main() {
describe('SelectorMatcher', () => {
var matcher, matched, selectableCollector, s1, s2, s3, s4;
function reset() {
matched = ListWrapper.create();
}
function reset() { matched = ListWrapper.create(); }
beforeEach(() => {
reset();
@ -18,52 +16,58 @@ export function main() {
selectableCollector = (selector, context) => {
ListWrapper.push(matched, selector);
ListWrapper.push(matched, context);
}
};
matcher = new SelectorMatcher();
});
it('should select by element name case insensitive', () => {
matcher.addSelectables(s1 = CssSelector.parse('someTag'), 1);
expect(matcher.match(CssSelector.parse('SOMEOTHERTAG')[0], selectableCollector)).toEqual(false);
expect(matcher.match(CssSelector.parse('SOMEOTHERTAG')[0], selectableCollector))
.toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('SOMETAG')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
expect(matched).toEqual([s1[0], 1]);
});
it('should select by class name case insensitive', () => {
matcher.addSelectables(s1 = CssSelector.parse('.someClass'), 1);
matcher.addSelectables(s2 = CssSelector.parse('.someClass.class2'), 2);
expect(matcher.match(CssSelector.parse('.SOMEOTHERCLASS')[0], selectableCollector)).toEqual(false);
expect(matcher.match(CssSelector.parse('.SOMEOTHERCLASS')[0], selectableCollector))
.toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('.SOMECLASS')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
expect(matched).toEqual([s1[0], 1]);
reset();
expect(matcher.match(CssSelector.parse('.someClass.class2')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1,s2[0],2]);
expect(matcher.match(CssSelector.parse('.someClass.class2')[0], selectableCollector))
.toEqual(true);
expect(matched).toEqual([s1[0], 1, s2[0], 2]);
});
it('should select by attr name case insensitive independent of the value', () => {
matcher.addSelectables(s1 = CssSelector.parse('[someAttr]'), 1);
matcher.addSelectables(s2 = CssSelector.parse('[someAttr][someAttr2]'), 2);
expect(matcher.match(CssSelector.parse('[SOMEOTHERATTR]')[0], selectableCollector)).toEqual(false);
expect(matcher.match(CssSelector.parse('[SOMEOTHERATTR]')[0], selectableCollector))
.toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('[SOMEATTR]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
expect(matched).toEqual([s1[0], 1]);
reset();
expect(matcher.match(CssSelector.parse('[SOMEATTR=someValue]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
expect(matcher.match(CssSelector.parse('[SOMEATTR=someValue]')[0], selectableCollector))
.toEqual(true);
expect(matched).toEqual([s1[0], 1]);
reset();
expect(matcher.match(CssSelector.parse('[someAttr][someAttr2]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1,s2[0],2]);
expect(matcher.match(CssSelector.parse('[someAttr][someAttr2]')[0], selectableCollector))
.toEqual(true);
expect(matched).toEqual([s1[0], 1, s2[0], 2]);
});
it('should select by attr name only once if the value is from the DOM', () => {
@ -74,36 +78,48 @@ export function main() {
var empty = DOM.getAttribute(element, 'attr');
elementSelector.addAttribute('some-decor', empty);
matcher.match(elementSelector, selectableCollector);
expect(matched).toEqual([s1[0],1]);
expect(matched).toEqual([s1[0], 1]);
});
it('should select by attr name and value case insensitive', () => {
matcher.addSelectables(s1 = CssSelector.parse('[someAttr=someValue]'), 1);
expect(matcher.match(CssSelector.parse('[SOMEATTR=SOMEOTHERATTR]')[0], selectableCollector)).toEqual(false);
expect(matcher.match(CssSelector.parse('[SOMEATTR=SOMEOTHERATTR]')[0], selectableCollector))
.toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('[SOMEATTR=SOMEVALUE]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
expect(matcher.match(CssSelector.parse('[SOMEATTR=SOMEVALUE]')[0], selectableCollector))
.toEqual(true);
expect(matched).toEqual([s1[0], 1]);
});
it('should select by element name, class name and attribute name with value', () => {
matcher.addSelectables(s1 = CssSelector.parse('someTag.someClass[someAttr=someValue]'), 1);
expect(matcher.match(CssSelector.parse('someOtherTag.someOtherClass[someOtherAttr]')[0], selectableCollector)).toEqual(false);
expect(matcher.match(CssSelector.parse('someOtherTag.someOtherClass[someOtherAttr]')[0],
selectableCollector))
.toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('someTag.someOtherClass[someOtherAttr]')[0], selectableCollector)).toEqual(false);
expect(matcher.match(CssSelector.parse('someTag.someOtherClass[someOtherAttr]')[0],
selectableCollector))
.toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('someTag.someClass[someOtherAttr]')[0], selectableCollector)).toEqual(false);
expect(matcher.match(CssSelector.parse('someTag.someClass[someOtherAttr]')[0],
selectableCollector))
.toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('someTag.someClass[someAttr]')[0], selectableCollector)).toEqual(false);
expect(
matcher.match(CssSelector.parse('someTag.someClass[someAttr]')[0], selectableCollector))
.toEqual(false);
expect(matched).toEqual([]);
expect(matcher.match(CssSelector.parse('someTag.someClass[someAttr=someValue]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
expect(matcher.match(CssSelector.parse('someTag.someClass[someAttr=someValue]')[0],
selectableCollector))
.toEqual(true);
expect(matched).toEqual([s1[0], 1]);
});
it('should select by many attributes and independent of the value', () => {
@ -124,20 +140,24 @@ export function main() {
matcher.addSelectables(s3 = CssSelector.parse('.class1.class2'), 3);
matcher.addSelectables(s4 = CssSelector.parse('.class2.class1'), 4);
expect(matcher.match(CssSelector.parse('[someAttr].someClass')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1,s2[0],2]);
expect(matcher.match(CssSelector.parse('[someAttr].someClass')[0], selectableCollector))
.toEqual(true);
expect(matched).toEqual([s1[0], 1, s2[0], 2]);
reset();
expect(matcher.match(CssSelector.parse('.someClass[someAttr]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1,s2[0],2]);
expect(matcher.match(CssSelector.parse('.someClass[someAttr]')[0], selectableCollector))
.toEqual(true);
expect(matched).toEqual([s1[0], 1, s2[0], 2]);
reset();
expect(matcher.match(CssSelector.parse('.class1.class2')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s3[0],3,s4[0],4]);
expect(matcher.match(CssSelector.parse('.class1.class2')[0], selectableCollector))
.toEqual(true);
expect(matched).toEqual([s3[0], 3, s4[0], 4]);
reset();
expect(matcher.match(CssSelector.parse('.class2.class1')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s4[0],4,s3[0],3]);
expect(matcher.match(CssSelector.parse('.class2.class1')[0], selectableCollector))
.toEqual(true);
expect(matched).toEqual([s4[0], 4, s3[0], 3]);
});
it('should not select with a matching :not selector', () => {
@ -147,7 +167,8 @@ export function main() {
matcher.addSelectables(CssSelector.parse(':not(p)'), 4);
matcher.addSelectables(CssSelector.parse(':not(p[someAttr])'), 5);
expect(matcher.match(CssSelector.parse('p.someClass[someAttr]')[0], selectableCollector)).toEqual(false);
expect(matcher.match(CssSelector.parse('p.someClass[someAttr]')[0], selectableCollector))
.toEqual(false);
expect(matched).toEqual([]);
});
@ -157,27 +178,31 @@ export function main() {
matcher.addSelectables(s3 = CssSelector.parse(':not(.someClass)'), 3);
matcher.addSelectables(s4 = CssSelector.parse(':not(.someOtherClass[someAttr])'), 4);
expect(matcher.match(CssSelector.parse('p[someOtherAttr].someOtherClass')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1,s2[0],2,s3[0],3,s4[0],4]);
expect(matcher.match(CssSelector.parse('p[someOtherAttr].someOtherClass')[0],
selectableCollector))
.toEqual(true);
expect(matched).toEqual([s1[0], 1, s2[0], 2, s3[0], 3, s4[0], 4]);
});
it('should select with one match in a list', () => {
matcher.addSelectables(s1 = CssSelector.parse('input[type=text], textbox'), 1);
matcher.addSelectables(s1 = CssSelector.parse('input[type=text], textbox'), 1);
expect(matcher.match(CssSelector.parse('textbox')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[1],1]);
expect(matcher.match(CssSelector.parse('textbox')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[1], 1]);
reset();
expect(matcher.match(CssSelector.parse('input[type=text]')[0], selectableCollector)).toEqual(true);
expect(matched).toEqual([s1[0],1]);
reset();
expect(matcher.match(CssSelector.parse('input[type=text]')[0], selectableCollector))
.toEqual(true);
expect(matched).toEqual([s1[0], 1]);
});
it('should not select twice with two matches in a list', () => {
matcher.addSelectables(s1 = CssSelector.parse('input, .someClass'), 1);
matcher.addSelectables(s1 = CssSelector.parse('input, .someClass'), 1);
expect(matcher.match(CssSelector.parse('input.someclass')[0], selectableCollector)).toEqual(true);
expect(matched.length).toEqual(2);
expect(matched).toEqual([s1[0],1]);
expect(matcher.match(CssSelector.parse('input.someclass')[0], selectableCollector))
.toEqual(true);
expect(matched.length).toEqual(2);
expect(matched).toEqual([s1[0], 1]);
});
});
@ -251,9 +276,8 @@ export function main() {
});
it('should throw when nested :not', () => {
expect(() => {
CssSelector.parse('sometag:not(:not([attrname=attrvalue].someclass))')[0];
}).toThrowError('Nesting :not is not allowed in a selector');
expect(() => { CssSelector.parse('sometag:not(:not([attrname=attrvalue].someclass))')[0]; })
.toThrowError('Nesting :not is not allowed in a selector');
});
it('should detect lists of selectors', () => {
@ -266,7 +290,8 @@ export function main() {
});
it('should detect lists of selectors with :not', () => {
var cssSelectors = CssSelector.parse('input[type=text], :not(textarea), textbox:not(.special)');
var cssSelectors =
CssSelector.parse('input[type=text], :not(textarea), textbox:not(.special)');
expect(cssSelectors.length).toEqual(3);
expect(cssSelectors[0].element).toEqual('input');

View File

@ -1,100 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
} from 'angular2/test_lib';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
import {UrlResolver} from 'angular2/src/services/url_resolver';
import {ViewDefinition} from 'angular2/src/render/api';
import {PromiseWrapper} from 'angular2/src/facade/async';
import {MockXHR} from 'angular2/src/mock/xhr_mock';
export function main() {
describe('TemplateLoader', () => {
var loader, xhr;
beforeEach(() => {
xhr = new MockXHR();
loader = new TemplateLoader(xhr, new FakeUrlResolver());
});
it('should load inline templates', inject([AsyncTestCompleter], (async) => {
var template = new ViewDefinition({template: 'template template'});
loader.load(template).then( (el) => {
expect(DOM.content(el)).toHaveText('template template');
async.done();
});
}));
it('should load templates through XHR', inject([AsyncTestCompleter], (async) => {
xhr.expect('base/foo', 'xhr template');
var template = new ViewDefinition({absUrl: 'base/foo'});
loader.load(template).then((el) => {
expect(DOM.content(el)).toHaveText('xhr template');
async.done();
});
xhr.flush();
}));
it('should cache template loaded through XHR but clone it as the compiler might change it', inject([AsyncTestCompleter], (async) => {
var firstEl;
// we have only one xhr.expect, so there can only be one xhr call!
xhr.expect('base/foo', 'xhr template');
var template = new ViewDefinition({absUrl: 'base/foo'});
loader.load(template)
.then((el) => {
expect(DOM.content(el)).toHaveText('xhr template');
firstEl = el;
return loader.load(template);
})
.then((el) =>{
expect(el).not.toBe(firstEl);
expect(DOM.content(el)).toHaveText('xhr template');
async.done();
});
xhr.flush();
}));
it('should throw when no template is defined', () => {
var template = new ViewDefinition({template: null, absUrl: null});
expect(() => loader.load(template))
.toThrowError('View should have either the url or template property set');
});
it('should return a rejected Promise when xhr loading fails', inject([AsyncTestCompleter], (async) => {
xhr.expect('base/foo', null);
var template = new ViewDefinition({absUrl: 'base/foo'});
PromiseWrapper.then(loader.load(template),
function(_) { throw 'Unexpected response'; },
function(error) {
expect(error).toEqual('Failed to load base/foo');
async.done();
}
)
xhr.flush();
}));
});
}
class SomeComponent {
}
class FakeUrlResolver extends UrlResolver {
constructor() {
super();
}
resolve(baseUrl: string, url: string): string {
return baseUrl + url;
}
}

View File

@ -0,0 +1,96 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
} from 'angular2/test_lib';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
import {UrlResolver} from 'angular2/src/services/url_resolver';
import {ViewDefinition} from 'angular2/src/render/api';
import {PromiseWrapper} from 'angular2/src/facade/async';
import {MockXHR} from 'angular2/src/mock/xhr_mock';
export function main() {
describe('TemplateLoader', () => {
var loader, xhr;
beforeEach(() => {
xhr = new MockXHR();
loader = new TemplateLoader(xhr, new FakeUrlResolver());
});
it('should load inline templates', inject([AsyncTestCompleter], (async) => {
var template = new ViewDefinition({template: 'template template'});
loader.load(template).then((el) => {
expect(DOM.content(el)).toHaveText('template template');
async.done();
});
}));
it('should load templates through XHR', inject([AsyncTestCompleter], (async) => {
xhr.expect('base/foo', 'xhr template');
var template = new ViewDefinition({absUrl: 'base/foo'});
loader.load(template).then((el) => {
expect(DOM.content(el)).toHaveText('xhr template');
async.done();
});
xhr.flush();
}));
it('should cache template loaded through XHR but clone it as the compiler might change it',
inject([AsyncTestCompleter], (async) => {
var firstEl;
// we have only one xhr.expect, so there can only be one xhr call!
xhr.expect('base/foo', 'xhr template');
var template = new ViewDefinition({absUrl: 'base/foo'});
loader.load(template)
.then((el) =>
{
expect(DOM.content(el)).toHaveText('xhr template');
firstEl = el;
return loader.load(template);
})
.then((el) => {
expect(el).not.toBe(firstEl);
expect(DOM.content(el)).toHaveText('xhr template');
async.done();
});
xhr.flush();
}));
it('should throw when no template is defined', () => {
var template = new ViewDefinition({template: null, absUrl: null});
expect(() => loader.load(template))
.toThrowError('View should have either the url or template property set');
});
it('should return a rejected Promise when xhr loading fails',
inject([AsyncTestCompleter], (async) => {
xhr.expect('base/foo', null);
var template = new ViewDefinition({absUrl: 'base/foo'});
PromiseWrapper.then(loader.load(template), function(_) { throw 'Unexpected response'; },
function(error) {
expect(error).toEqual('Failed to load base/foo');
async.done();
});
xhr.flush();
}));
});
}
class SomeComponent {}
class FakeUrlResolver extends UrlResolver {
constructor() { super(); }
resolve(baseUrl: string, url: string): string { return baseUrl + url; }
}

View File

@ -4,21 +4,18 @@ import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline
import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {Lexer, Parser} from 'angular2/change_detection';
import {IgnoreChildrenStep} from './pipeline_spec';
import {ElementBinderBuilder} from 'angular2/src/render/dom/view/proto_view_builder';
export function main() {
describe('TextInterpolationParser', () => {
function createPipeline() {
return new CompilePipeline([
new IgnoreChildrenStep(),
new TextInterpolationParser(new Parser(new Lexer()))
]);
return new CompilePipeline(
[new IgnoreChildrenStep(), new TextInterpolationParser(new Parser(new Lexer()))]);
}
function process(element) {
return ListWrapper.map(
createPipeline().process(element),
(compileElement) => compileElement.inheritedElementBinder
);
function process(element): List<ElementBinderBuilder> {
return ListWrapper.map(createPipeline().process(element),
(compileElement) => compileElement.inheritedElementBinder);
}
function assertTextBinding(elementBinder, bindingIndex, nodeIndex, expression) {

View File

@ -21,7 +21,8 @@ export function main() {
var rootElement = el('<div><template if="true">a</template></div>');
var results = createPipeline().process(rootElement);
expect(DOM.getOuterHTML(results[1].element)).toEqual('<template if="true" class="ng-binding"></template>');
expect(DOM.getOuterHTML(results[1].element))
.toEqual('<template if="true" class="ng-binding"></template>');
expect(results[1].isViewRoot).toBe(false);
expect(DOM.getOuterHTML(results[2].element)).toEqual('<template>a</template>');
expect(results[2].isViewRoot).toBe(true);
@ -56,9 +57,11 @@ export function main() {
var rootElement = el('<div><template if="true">a</template></div>');
var results = createPipeline().process(rootElement);
expect(results[2].inheritedProtoView).not.toBe(null);
expect(results[2].inheritedProtoView).toBe(results[1].inheritedElementBinder.nestedProtoView);
expect(results[2].inheritedProtoView)
.toBe(results[1].inheritedElementBinder.nestedProtoView);
expect(results[2].inheritedProtoView.type).toBe(ProtoViewDto.EMBEDDED_VIEW_TYPE);
expect(DOM.getOuterHTML(results[2].inheritedProtoView.rootElement)).toEqual('<template>a</template>');
expect(DOM.getOuterHTML(results[2].inheritedProtoView.rootElement))
.toEqual('<template>a</template>');
});
});
@ -70,8 +73,9 @@ export function main() {
var originalChild = rootElement.childNodes[0];
var results = createPipeline().process(rootElement);
expect(results[0].element).toBe(rootElement);
expect(DOM.getOuterHTML(results[0].element)).toEqual('<div><template class="ng-binding"></template></div>');
expect(DOM.getOuterHTML(results[2].element)).toEqual('<span template=""></span>')
expect(DOM.getOuterHTML(results[0].element))
.toEqual('<div><template class="ng-binding"></template></div>');
expect(DOM.getOuterHTML(results[2].element)).toEqual('<span template=""></span>');
expect(results[2].element).toBe(originalChild);
});
@ -83,7 +87,8 @@ export function main() {
expect(results[0].element).toBe(rootElement);
expect(results[0].isViewRoot).toBe(true);
expect(results[2].isViewRoot).toBe(true);
expect(DOM.getOuterHTML(results[0].element)).toEqual('<template><template class="ng-binding"></template></template>');
expect(DOM.getOuterHTML(results[0].element))
.toEqual('<template><template class="ng-binding"></template></template>');
expect(results[2].element).toBe(originalChild);
});
@ -96,14 +101,17 @@ export function main() {
it('should add property bindings from the template attribute', () => {
var rootElement = el('<div><div template="some-prop:expr"></div></div>');
var results = createPipeline().process(rootElement);
expect(MapWrapper.get(results[1].inheritedElementBinder.propertyBindings, 'someProp').source).toEqual('expr');
expect(
MapWrapper.get(results[1].inheritedElementBinder.propertyBindings, 'someProp').source)
.toEqual('expr');
expect(MapWrapper.get(results[1].attrs(), 'some-prop')).toEqual('expr');
});
it('should add variable mappings from the template attribute to the nestedProtoView', () => {
var rootElement = el('<div><div template="var var-name=mapName"></div></div>');
var results = createPipeline().process(rootElement);
expect(results[2].inheritedProtoView.variableBindings).toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
expect(results[2].inheritedProtoView.variableBindings)
.toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
});
it('should add entries without value as attributes to the element', () => {
@ -137,8 +145,10 @@ export function main() {
var rootElement = el('<div><span template=""></span></div>');
var results = createPipeline().process(rootElement);
expect(results[2].inheritedProtoView).not.toBe(null);
expect(results[2].inheritedProtoView).toBe(results[1].inheritedElementBinder.nestedProtoView);
expect(DOM.getOuterHTML(results[2].inheritedProtoView.rootElement)).toEqual('<span template=""></span>');
expect(results[2].inheritedProtoView)
.toBe(results[1].inheritedElementBinder.nestedProtoView);
expect(DOM.getOuterHTML(results[2].inheritedProtoView.rootElement))
.toEqual('<span template=""></span>');
});
});
@ -150,8 +160,9 @@ export function main() {
var originalChild = rootElement.childNodes[0];
var results = createPipeline().process(rootElement);
expect(results[0].element).toBe(rootElement);
expect(DOM.getOuterHTML(results[0].element)).toEqual('<div><template class="ng-binding" ng-if=""></template></div>');
expect(DOM.getOuterHTML(results[2].element)).toEqual('<span *ng-if=""></span>')
expect(DOM.getOuterHTML(results[0].element))
.toEqual('<div><template class="ng-binding" ng-if=""></template></div>');
expect(DOM.getOuterHTML(results[2].element)).toEqual('<span *ng-if=""></span>');
expect(results[2].element).toBe(originalChild);
});
@ -169,21 +180,24 @@ export function main() {
expect(results[0].element).toBe(rootElement);
expect(results[0].isViewRoot).toBe(true);
expect(results[2].isViewRoot).toBe(true);
expect(DOM.getOuterHTML(results[0].element)).toEqual('<template><template class="ng-binding" foo=""></template></template>');
expect(DOM.getOuterHTML(results[0].element))
.toEqual('<template><template class="ng-binding" foo=""></template></template>');
expect(results[2].element).toBe(originalChild);
});
it('should add property bindings from the template attribute', () => {
var rootElement = el('<div><div *prop="expr"></div></div>');
var results = createPipeline().process(rootElement);
expect(MapWrapper.get(results[1].inheritedElementBinder.propertyBindings, 'prop').source).toEqual('expr');
expect(MapWrapper.get(results[1].inheritedElementBinder.propertyBindings, 'prop').source)
.toEqual('expr');
expect(MapWrapper.get(results[1].attrs(), 'prop')).toEqual('expr');
});
it('should add variable mappings from the template attribute to the nestedProtoView', () => {
var rootElement = el('<div><div *foreach="var varName=mapName"></div></div>');
var results = createPipeline().process(rootElement);
expect(results[2].inheritedProtoView.variableBindings).toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
expect(results[2].inheritedProtoView.variableBindings)
.toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
});
it('should add entries without value as attribute to the element', () => {
@ -217,8 +231,10 @@ export function main() {
var rootElement = el('<div><span *foo></span></div>');
var results = createPipeline().process(rootElement);
expect(results[2].inheritedProtoView).not.toBe(null);
expect(results[2].inheritedProtoView).toBe(results[1].inheritedElementBinder.nestedProtoView);
expect(DOM.getOuterHTML(results[2].inheritedProtoView.rootElement)).toEqual('<span *foo=""></span>');
expect(results[2].inheritedProtoView)
.toBe(results[1].inheritedElementBinder.nestedProtoView);
expect(DOM.getOuterHTML(results[2].inheritedProtoView.rootElement))
.toEqual('<span *foo=""></span>');
});
});

View File

@ -1,7 +1,6 @@
import {MapWrapper} from 'angular2/src/facade/collection';
import {DirectiveMetadata} from 'angular2/src/render/api';
import {directiveMetadataFromMap, directiveMetadataToMap} from
'angular2/src/render/dom/convert';
import {directiveMetadataFromMap, directiveMetadataToMap} from 'angular2/src/render/dom/convert';
import {ddescribe, describe, expect, it} from 'angular2/test_lib';
export function main() {
@ -10,10 +9,8 @@ export function main() {
var someComponent = new DirectiveMetadata({
compileChildren: false,
hostListeners: MapWrapper.createFromPairs([['listenKey', 'listenVal']]),
hostProperties:
MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]),
hostActions:
MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]),
hostProperties: MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]),
hostActions: MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]),
id: 'someComponent',
properties: MapWrapper.createFromPairs([['propKey', 'propVal']]),
readAttributes: ['read1', 'read2'],
@ -22,29 +19,26 @@ export function main() {
});
var map = directiveMetadataToMap(someComponent);
expect(MapWrapper.get(map, 'compileChildren')).toEqual(false);
expect(MapWrapper.get(map, 'hostListeners')).toEqual(
MapWrapper.createFromPairs([['listenKey', 'listenVal']]));
expect(MapWrapper.get(map, 'hostProperties')).toEqual(
MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]));
expect(MapWrapper.get(map, 'hostActions')).toEqual(
MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]));
expect(MapWrapper.get(map, 'hostListeners'))
.toEqual(MapWrapper.createFromPairs([['listenKey', 'listenVal']]));
expect(MapWrapper.get(map, 'hostProperties'))
.toEqual(MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]));
expect(MapWrapper.get(map, 'hostActions'))
.toEqual(MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]));
expect(MapWrapper.get(map, 'id')).toEqual('someComponent');
expect(MapWrapper.get(map, 'properties')).toEqual(
MapWrapper.createFromPairs([['propKey', 'propVal']]));
expect(MapWrapper.get(map, 'properties'))
.toEqual(MapWrapper.createFromPairs([['propKey', 'propVal']]));
expect(MapWrapper.get(map, 'readAttributes')).toEqual(['read1', 'read2']);
expect(MapWrapper.get(map, 'selector')).toEqual('some-comp');
expect(MapWrapper.get(map, 'type')).toEqual(
DirectiveMetadata.COMPONENT_TYPE);
expect(MapWrapper.get(map, 'type')).toEqual(DirectiveMetadata.COMPONENT_TYPE);
});
it('mapToDirectiveMetadata', () => {
var map = MapWrapper.createFromPairs([
['compileChildren', false],
['hostListeners', MapWrapper.createFromPairs([['testKey', 'testVal']])],
['hostProperties',
MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']])],
['hostActions',
MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']])],
['hostProperties', MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']])],
['hostActions', MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']])],
['id', 'testId'],
['properties', MapWrapper.createFromPairs([['propKey', 'propVal']])],
['readAttributes', ['readTest1', 'readTest2']],
@ -53,15 +47,13 @@ export function main() {
]);
var meta = directiveMetadataFromMap(map);
expect(meta.compileChildren).toEqual(false);
expect(meta.hostListeners).toEqual(
MapWrapper.createFromPairs([['testKey', 'testVal']]));
expect(meta.hostProperties).toEqual(
MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]));
expect(meta.hostActions).toEqual(
MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]));
expect(meta.hostListeners).toEqual(MapWrapper.createFromPairs([['testKey', 'testVal']]));
expect(meta.hostProperties)
.toEqual(MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]));
expect(meta.hostActions)
.toEqual(MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]));
expect(meta.id).toEqual('testId');
expect(meta.properties).toEqual(
MapWrapper.createFromPairs([['propKey', 'propVal']]));
expect(meta.properties).toEqual(MapWrapper.createFromPairs([['propKey', 'propVal']]));
expect(meta.readAttributes).toEqual(['readTest1', 'readTest2']);
expect(meta.selector).toEqual('testSelector');
expect(meta.type).toEqual(DirectiveMetadata.DIRECTIVE_TYPE);

View File

@ -1,197 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
el,
elementText,
expect,
iit,
inject,
it,
xit,
beforeEachBindings,
SpyObject,
} from 'angular2/test_lib';
import {MapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {DomTestbed, TestView} from './dom_testbed';
import {ViewDefinition, DirectiveMetadata, RenderViewRef} from 'angular2/src/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) => {
tb.compiler.compileHost(someComponent).then( (hostProtoViewDto) => {
var view = new TestView(tb.renderer.createRootHostView(hostProtoViewDto.render, '#root'));
expect(view.rawView.rootNodes[0]).toEqual(tb.rootEl);
tb.renderer.destroyView(view.viewRef);
// destroying a root view should not disconnect it!
expect(tb.rootEl.parentNode).toBeTruthy();
async.done();
});
}));
it('should create and destroy free host views',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compiler.compileHost(someComponent).then( (hostProtoViewDto) => {
var view = new TestView(tb.renderer.createView(hostProtoViewDto.render));
var hostElement = tb.renderer.getHostElement(view.viewRef);
DOM.appendChild(tb.rootEl, hostElement);
tb.renderer.detachFreeHostView(null, view.viewRef);
expect(DOM.parentElement(hostElement)).toBeFalsy();
async.done();
});
}));
it('should attach and detach component views',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
someComponent,
new ViewDefinition({
componentId: 'someComponent',
template: 'hello',
directives: []
})
]).then( (protoViewDtos) => {
var rootView = tb.createRootView(protoViewDtos[0]);
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
expect(tb.rootEl).toHaveText('hello');
tb.destroyComponentView(rootView.viewRef, 0, cmpView.viewRef);
expect(tb.rootEl).toHaveText('');
async.done();
});
}));
it('should update text nodes',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([someComponent,
new ViewDefinition({
componentId: 'someComponent',
template: '{{a}}',
directives: []
})
]).then( (protoViewDtos) => {
var rootView = tb.createRootView(protoViewDtos[0]);
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
tb.renderer.setText(cmpView.viewRef, 0, 'hello');
expect(tb.rootEl).toHaveText('hello');
async.done();
});
}));
it('should update element properties',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([someComponent,
new ViewDefinition({
componentId: 'someComponent',
template: '<input [value]="someProp">asdf',
directives: []
})
]).then( (protoViewDtos) => {
var rootView = tb.createRootView(protoViewDtos[0]);
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
tb.renderer.setElementProperty(cmpView.viewRef, 0, 'value', 'hello');
expect(DOM.childNodes(tb.rootEl)[0].value).toEqual('hello');
async.done();
});
}));
it('should call actions on the element',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([someComponent,
new ViewDefinition({
componentId: 'someComponent',
template: '<input with-host-actions></input>',
directives: [directiveWithHostActions]
})
]).then( (protoViewDtos) => {
var views = tb.createRootViews(protoViewDtos);
var componentView = views[1];
tb.renderer.callAction(componentView.viewRef, 0, 'value = "val"', null);
expect(DOM.getValue(DOM.childNodes(tb.rootEl)[0])).toEqual('val');
async.done();
});
}));
it('should add and remove views to and from containers',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([someComponent,
new ViewDefinition({
componentId: 'someComponent',
template: '<template>hello</template>',
directives: []
})
]).then( (protoViewDtos) => {
var rootView = tb.createRootView(protoViewDtos[0]);
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
var childProto = protoViewDtos[1].elementBinders[0].nestedProtoView;
expect(tb.rootEl).toHaveText('');
var childView = tb.createViewInContainer(cmpView.viewRef, 0, 0, childProto);
expect(tb.rootEl).toHaveText('hello');
tb.destroyViewInContainer(cmpView.viewRef, 0, 0, childView.viewRef);
expect(tb.rootEl).toHaveText('');
async.done();
});
}));
it('should handle events',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([someComponent,
new ViewDefinition({
componentId: 'someComponent',
template: '<input (change)="doSomething()">',
directives: []
})
]).then( (protoViewDtos) => {
var rootView = tb.createRootView(protoViewDtos[0]);
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
tb.triggerEvent(cmpView.viewRef, 0, 'change');
var eventEntry = cmpView.events[0];
// bound element index
expect(eventEntry[0]).toEqual(0);
// event type
expect(eventEntry[1]).toEqual('change');
// actual event
expect(MapWrapper.get(eventEntry[2], '$event').type).toEqual('change');
async.done();
});
}));
});
}
var someComponent = new DirectiveMetadata({
id: 'someComponent',
type: DirectiveMetadata.COMPONENT_TYPE,
selector: 'some-comp'
});
var directiveWithHostActions = new DirectiveMetadata({
id: 'withHostActions',
type: DirectiveMetadata.DIRECTIVE_TYPE,
selector: '[with-host-actions]',
hostActions: MapWrapper.createFromStringMap({
'setValue' : 'value = "val"'
})
});

View File

@ -0,0 +1,194 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
beforeEachBindings,
SpyObject,
} from 'angular2/test_lib';
import {MapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {DomTestbed, TestView} from './dom_testbed';
import {ViewDefinition, DirectiveMetadata, RenderViewRef} from 'angular2/src/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) => {
tb.compiler.compileHost(someComponent)
.then((hostProtoViewDto) => {
var view =
new TestView(tb.renderer.createRootHostView(hostProtoViewDto.render, '#root'));
expect(view.rawView.rootNodes[0]).toEqual(tb.rootEl);
tb.renderer.destroyView(view.viewRef);
// destroying a root view should not disconnect it!
expect(tb.rootEl.parentNode).toBeTruthy();
async.done();
});
}));
it('should create and destroy free host views',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compiler.compileHost(someComponent)
.then((hostProtoViewDto) => {
var view = new TestView(tb.renderer.createView(hostProtoViewDto.render));
var hostElement = tb.renderer.getHostElement(view.viewRef);
DOM.appendChild(tb.rootEl, hostElement);
tb.renderer.detachFreeHostView(null, view.viewRef);
expect(DOM.parentElement(hostElement)).toBeFalsy();
async.done();
});
}));
it('should attach and detach component views',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
someComponent,
new ViewDefinition(
{componentId: 'someComponent', template: 'hello', directives: []})
])
.then((protoViewDtos) => {
var rootView = tb.createRootView(protoViewDtos[0]);
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
expect(tb.rootEl).toHaveText('hello');
tb.destroyComponentView(rootView.viewRef, 0, cmpView.viewRef);
expect(tb.rootEl).toHaveText('');
async.done();
});
}));
it('should update text nodes', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
someComponent,
new ViewDefinition(
{componentId: 'someComponent', template: '{{a}}', directives: []})
])
.then((protoViewDtos) => {
var rootView = tb.createRootView(protoViewDtos[0]);
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
tb.renderer.setText(cmpView.viewRef, 0, 'hello');
expect(tb.rootEl).toHaveText('hello');
async.done();
});
}));
it('should update element properties', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
someComponent,
new ViewDefinition({
componentId: 'someComponent',
template: '<input [value]="someProp">asdf',
directives: []
})
])
.then((protoViewDtos) => {
var rootView = tb.createRootView(protoViewDtos[0]);
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
tb.renderer.setElementProperty(cmpView.viewRef, 0, 'value', 'hello');
expect(DOM.childNodes(tb.rootEl)[0].value).toEqual('hello');
async.done();
});
}));
it('should call actions on the element',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
someComponent,
new ViewDefinition({
componentId: 'someComponent',
template: '<input with-host-actions></input>',
directives: [directiveWithHostActions]
})
])
.then((protoViewDtos) => {
var views = tb.createRootViews(protoViewDtos);
var componentView = views[1];
tb.renderer.callAction(componentView.viewRef, 0, 'value = "val"', null);
expect(DOM.getValue(DOM.childNodes(tb.rootEl)[0])).toEqual('val');
async.done();
});
}));
it('should add and remove views to and from containers',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
someComponent,
new ViewDefinition({
componentId: 'someComponent',
template: '<template>hello</template>',
directives: []
})
])
.then((protoViewDtos) => {
var rootView = tb.createRootView(protoViewDtos[0]);
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
var childProto = protoViewDtos[1].elementBinders[0].nestedProtoView;
expect(tb.rootEl).toHaveText('');
var childView = tb.createViewInContainer(cmpView.viewRef, 0, 0, childProto);
expect(tb.rootEl).toHaveText('hello');
tb.destroyViewInContainer(cmpView.viewRef, 0, 0, childView.viewRef);
expect(tb.rootEl).toHaveText('');
async.done();
});
}));
it('should handle events', inject([AsyncTestCompleter, DomTestbed], (async, tb: DomTestbed) => {
tb.compileAll([
someComponent,
new ViewDefinition({
componentId: 'someComponent',
template: '<input (change)="doSomething()">',
directives: []
})
])
.then((protoViewDtos) => {
var rootView = tb.createRootView(protoViewDtos[0]);
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
tb.triggerEvent(cmpView.viewRef, 0, 'change');
var eventEntry = cmpView.events[0];
// bound element index
expect(eventEntry[0]).toEqual(0);
// event type
expect(eventEntry[1]).toEqual('change');
// actual event
expect((<any>MapWrapper.get(eventEntry[2], '$event')).type).toEqual('change');
async.done();
});
}));
});
}
var someComponent = new DirectiveMetadata(
{id: 'someComponent', type: DirectiveMetadata.COMPONENT_TYPE, selector: 'some-comp'});
var directiveWithHostActions = new DirectiveMetadata({
id: 'withHostActions',
type: DirectiveMetadata.DIRECTIVE_TYPE,
selector: '[with-host-actions]',
hostActions: MapWrapper.createFromStringMap({'setValue': 'value = "val"'})
});

View File

@ -1,4 +1,4 @@
import {Inject, Injectable} from 'angular2/src/di/annotations_impl';
import {Inject, Injectable} from 'angular2/di';
import {MapWrapper, ListWrapper, List, Map} from 'angular2/src/facade/collection';
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
import {DOM} from 'angular2/src/dom/dom_adapter';
@ -6,16 +6,22 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
import {DomRenderer, DOCUMENT_TOKEN} from 'angular2/src/render/dom/dom_renderer';
import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler';
import {DomView} from 'angular2/src/render/dom/view/view';
import {RenderViewRef, ProtoViewDto, ViewDefinition, EventDispatcher, DirectiveMetadata} from 'angular2/src/render/api';
import {
RenderViewRef,
ProtoViewDto,
ViewDefinition,
EventDispatcher,
DirectiveMetadata
} from 'angular2/src/render/api';
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
import {el, dispatchEvent} from 'angular2/test_lib';
export class TestView {
rawView:DomView;
viewRef:RenderViewRef;
events:List;
rawView: DomView;
viewRef: RenderViewRef;
events: List<List<any>>;
constructor(viewRef:RenderViewRef) {
constructor(viewRef: RenderViewRef) {
this.viewRef = viewRef;
this.rawView = resolveInternalDomView(viewRef);
this.events = [];
@ -23,17 +29,12 @@ export class TestView {
}
@IMPLEMENTS(EventDispatcher)
class LoggingEventDispatcher {
log:List;
class LoggingEventDispatcher implements EventDispatcher {
log: List<List<any>>;
constructor(log:List) {
this.log = log;
}
constructor(log: List<List<any>>) { this.log = log; }
dispatchEvent(
elementIndex:number, eventName:string, locals:Map<string, any>
) {
dispatchEvent(elementIndex: number, eventName: string, locals: Map<string, any>) {
ListWrapper.push(this.log, [elementIndex, eventName, locals]);
return true;
}
@ -42,84 +43,87 @@ class LoggingEventDispatcher {
@Injectable()
export class DomTestbed {
renderer:DomRenderer;
compiler:DefaultDomCompiler;
renderer: DomRenderer;
compiler: DefaultDomCompiler;
rootEl;
constructor(renderer:DomRenderer, compiler:DefaultDomCompiler, @Inject(DOCUMENT_TOKEN) document) {
constructor(renderer: DomRenderer, compiler: DefaultDomCompiler,
@Inject(DOCUMENT_TOKEN) document) {
this.renderer = renderer;
this.compiler = compiler;
this.rootEl = el('<div id="root"></div>');
var oldRoots = DOM.querySelectorAll(document, '#root');
for (var i=0; i<oldRoots.length; i++) {
for (var i = 0; i < oldRoots.length; i++) {
DOM.remove(oldRoots[i]);
}
DOM.appendChild(DOM.querySelector(document, 'body'), this.rootEl);
}
compileAll(directivesOrViewDefinitions:List):Promise<List<ProtoViewDto>> {
return PromiseWrapper.all(
ListWrapper.map(directivesOrViewDefinitions, (entry) => {
if (entry instanceof DirectiveMetadata) {
return this.compiler.compileHost(entry);
} else {
return this.compiler.compile(entry);
}
})
);
compileAll(directivesOrViewDefinitions: List<DirectiveMetadata |
ViewDefinition>): Promise<List<ProtoViewDto>> {
return PromiseWrapper.all(ListWrapper.map(directivesOrViewDefinitions, (entry) => {
if (entry instanceof DirectiveMetadata) {
return this.compiler.compileHost(entry);
} else {
return this.compiler.compile(entry);
}
}));
}
_createTestView(viewRef:RenderViewRef) {
_createTestView(viewRef: RenderViewRef) {
var testView = new TestView(viewRef);
this.renderer.setEventDispatcher(viewRef, new LoggingEventDispatcher(testView.events));
return testView;
}
createRootView(rootProtoView:ProtoViewDto):TestView {
createRootView(rootProtoView: ProtoViewDto): TestView {
var viewRef = this.renderer.createRootHostView(rootProtoView.render, '#root');
this.renderer.hydrateView(viewRef);
return this._createTestView(viewRef);
}
createComponentView(parentViewRef:RenderViewRef, boundElementIndex:number, componentProtoView:ProtoViewDto):TestView {
createComponentView(parentViewRef: RenderViewRef, boundElementIndex: number,
componentProtoView: ProtoViewDto): TestView {
var componentViewRef = this.renderer.createView(componentProtoView.render);
this.renderer.attachComponentView(parentViewRef, boundElementIndex, componentViewRef);
this.renderer.hydrateView(componentViewRef);
return this._createTestView(componentViewRef);
}
createRootViews(protoViews:List<ProtoViewDto>):List<TestView> {
createRootViews(protoViews: List<ProtoViewDto>): List<TestView> {
var views = [];
var lastView = this.createRootView(protoViews[0]);
ListWrapper.push(views, lastView);
for (var i=1; i<protoViews.length; i++) {
for (var i = 1; i < protoViews.length; i++) {
lastView = this.createComponentView(lastView.viewRef, 0, protoViews[i]);
ListWrapper.push(views, lastView);
}
return views;
}
destroyComponentView(parentViewRef:RenderViewRef, boundElementIndex:number, componentView:RenderViewRef) {
destroyComponentView(parentViewRef: RenderViewRef, boundElementIndex: number,
componentView: RenderViewRef) {
this.renderer.dehydrateView(componentView);
this.renderer.detachComponentView(parentViewRef, boundElementIndex, componentView);
}
createViewInContainer(parentViewRef:RenderViewRef, boundElementIndex:number, atIndex:number, protoView:ProtoViewDto):TestView {
createViewInContainer(parentViewRef: RenderViewRef, boundElementIndex: number, atIndex: number,
protoView: ProtoViewDto): TestView {
var viewRef = this.renderer.createView(protoView.render);
this.renderer.attachViewInContainer(parentViewRef, boundElementIndex, atIndex, viewRef);
this.renderer.hydrateView(viewRef);
return this._createTestView(viewRef);
}
destroyViewInContainer(parentViewRef:RenderViewRef, boundElementIndex:number, atIndex:number, viewRef:RenderViewRef) {
destroyViewInContainer(parentViewRef: RenderViewRef, boundElementIndex: number, atIndex: number,
viewRef: RenderViewRef) {
this.renderer.dehydrateView(viewRef);
this.renderer.detachViewInContainer(parentViewRef, boundElementIndex, atIndex, viewRef);
this.renderer.destroyView(viewRef);
}
triggerEvent(viewRef:RenderViewRef, boundElementIndex:number, eventName:string) {
triggerEvent(viewRef: RenderViewRef, boundElementIndex: number, eventName: string) {
var element = resolveInternalDomView(viewRef).boundElements[boundElementIndex];
dispatchEvent(element, eventName);
}
}

View File

@ -1,5 +1,19 @@
import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, el} from 'angular2/test_lib';
import {EventManager, EventManagerPlugin, DomEventsPlugin} from 'angular2/src/render/dom/events/event_manager';
import {
describe,
ddescribe,
it,
iit,
xit,
xdescribe,
expect,
beforeEach,
el
} from 'angular2/test_lib';
import {
EventManager,
EventManagerPlugin,
DomEventsPlugin
} from 'angular2/src/render/dom/events/event_manager';
import {NgZone} from 'angular2/src/core/zone/ng_zone';
import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter';
@ -7,9 +21,7 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
export function main() {
var domEventPlugin;
beforeEach(() => {
domEventPlugin = new DomEventsPlugin();
});
beforeEach(() => { domEventPlugin = new DomEventsPlugin(); });
describe('EventManager', () => {
@ -35,7 +47,7 @@ export function main() {
var element = el('<div></div>');
var clickHandler = (e) => e;
var dblClickHandler = (e) => e;
var plugin1= new FakeEventManagerPlugin(['dblclick']);
var plugin1 = new FakeEventManagerPlugin(['dblclick']);
var plugin2 = new FakeEventManagerPlugin(['click', 'dblclick']);
var manager = new EventManager([plugin1, plugin2], new FakeNgZone());
manager.addEventListener(element, 'click', clickHandler);
@ -51,7 +63,7 @@ export function main() {
var plugin = new FakeEventManagerPlugin(['dblclick']);
var manager = new EventManager([plugin], new FakeNgZone());
expect(() => manager.addEventListener(element, 'click', null))
.toThrowError('No event manager plugin found for event click');
.toThrowError('No event manager plugin found for event click');
});
it('by default events are only caught on same element', () => {
@ -109,8 +121,8 @@ export function main() {
class FakeEventManagerPlugin extends EventManagerPlugin {
_supports: List<string>;
_nonBubbleEventHandlers: Map;
_bubbleEventHandlers: Map;
_nonBubbleEventHandlers: Map<string, Function>;
_bubbleEventHandlers: Map<string, Function>;
constructor(supports: List<string>) {
super();
this._supports = supports;
@ -118,28 +130,22 @@ class FakeEventManagerPlugin extends EventManagerPlugin {
this._bubbleEventHandlers = MapWrapper.create();
}
supports(eventName: string): boolean {
return ListWrapper.contains(this._supports, eventName);
}
supports(eventName: string): boolean { return ListWrapper.contains(this._supports, eventName); }
addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) {
MapWrapper.set(shouldSupportBubble ? this._bubbleEventHandlers : this._nonBubbleEventHandlers,
eventName, handler);
return () => {MapWrapper.delete(shouldSupportBubble ? this._bubbleEventHandlers : this._nonBubbleEventHandlers,
eventName)};
eventName, handler);
return () => {
MapWrapper.delete(
shouldSupportBubble ? this._bubbleEventHandlers : this._nonBubbleEventHandlers, eventName)
};
}
}
class FakeNgZone extends NgZone {
constructor() {
super({enableLongStackTrace: false});
}
constructor() { super({enableLongStackTrace: false}); }
run(fn) {
fn();
}
run(fn) { fn(); }
runOutsideAngular(fn) {
return fn();
}
runOutsideAngular(fn) { return fn(); }
}

View File

@ -1,4 +1,14 @@
import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, el} from 'angular2/test_lib';
import {
describe,
ddescribe,
it,
iit,
xit,
xdescribe,
expect,
beforeEach,
el
} from 'angular2/test_lib';
import {KeyEventsPlugin} from 'angular2/src/render/dom/events/key_events';
export function main() {
@ -15,53 +25,33 @@ export function main() {
it('should correctly parse event names', () => {
// key with no modifier
expect(KeyEventsPlugin.parseEventName('keydown.enter')).toEqual({
'domEventName': 'keydown',
'fullKey': 'enter'
});
expect(KeyEventsPlugin.parseEventName('keyup.enter')).toEqual({
'domEventName': 'keyup',
'fullKey': 'enter'
});
expect(KeyEventsPlugin.parseEventName('keydown.enter'))
.toEqual({'domEventName': 'keydown', 'fullKey': 'enter'});
expect(KeyEventsPlugin.parseEventName('keyup.enter'))
.toEqual({'domEventName': 'keyup', 'fullKey': 'enter'});
// key with modifiers:
expect(KeyEventsPlugin.parseEventName('keydown.control.shift.enter')).toEqual({
'domEventName': 'keydown',
'fullKey': 'control.shift.enter'
});
expect(KeyEventsPlugin.parseEventName('keyup.control.shift.enter')).toEqual({
'domEventName': 'keyup',
'fullKey': 'control.shift.enter'
});
expect(KeyEventsPlugin.parseEventName('keydown.control.shift.enter'))
.toEqual({'domEventName': 'keydown', 'fullKey': 'control.shift.enter'});
expect(KeyEventsPlugin.parseEventName('keyup.control.shift.enter'))
.toEqual({'domEventName': 'keyup', 'fullKey': 'control.shift.enter'});
// key with modifiers in a different order:
expect(KeyEventsPlugin.parseEventName('keydown.shift.control.enter')).toEqual({
'domEventName': 'keydown',
'fullKey': 'control.shift.enter'
});
expect(KeyEventsPlugin.parseEventName('keyup.shift.control.enter')).toEqual({
'domEventName': 'keyup',
'fullKey': 'control.shift.enter'
});
expect(KeyEventsPlugin.parseEventName('keydown.shift.control.enter'))
.toEqual({'domEventName': 'keydown', 'fullKey': 'control.shift.enter'});
expect(KeyEventsPlugin.parseEventName('keyup.shift.control.enter'))
.toEqual({'domEventName': 'keyup', 'fullKey': 'control.shift.enter'});
// key that is also a modifier:
expect(KeyEventsPlugin.parseEventName('keydown.shift.control')).toEqual({
'domEventName': 'keydown',
'fullKey': 'shift.control'
});
expect(KeyEventsPlugin.parseEventName('keyup.shift.control')).toEqual({
'domEventName': 'keyup',
'fullKey': 'shift.control'
});
expect(KeyEventsPlugin.parseEventName('keydown.shift.control'))
.toEqual({'domEventName': 'keydown', 'fullKey': 'shift.control'});
expect(KeyEventsPlugin.parseEventName('keyup.shift.control'))
.toEqual({'domEventName': 'keyup', 'fullKey': 'shift.control'});
expect(KeyEventsPlugin.parseEventName('keydown.control.shift')).toEqual({
'domEventName': 'keydown',
'fullKey': 'control.shift'
});
expect(KeyEventsPlugin.parseEventName('keyup.control.shift')).toEqual({
'domEventName': 'keyup',
'fullKey': 'control.shift'
});
expect(KeyEventsPlugin.parseEventName('keydown.control.shift'))
.toEqual({'domEventName': 'keydown', 'fullKey': 'control.shift'});
expect(KeyEventsPlugin.parseEventName('keyup.control.shift'))
.toEqual({'domEventName': 'keyup', 'fullKey': 'control.shift'});
});

View File

@ -1,12 +1,16 @@
import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el, proxy} from 'angular2/test_lib';
import {IMPLEMENTS} from 'angular2/src/facade/lang';
import {
describe,
beforeEach,
it,
expect,
ddescribe,
iit,
SpyObject,
el,
proxy
} from 'angular2/test_lib';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {Content} from 'angular2/src/render/dom/shadow_dom/content_tag';
import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom';
@proxy
@IMPLEMENTS(LightDom)
class DummyLightDom extends SpyObject {noSuchMethod(m){super.noSuchMethod(m)}}
var _scriptStart = `<script start=""></script>`;
var _scriptEnd = `<script end=""></script>`;
@ -26,7 +30,8 @@ export function main() {
c.init(null);
c.insert([el("<a></a>"), el("<b></b>")])
expect(DOM.getInnerHTML(parent)).toEqual(`${_scriptStart}<a></a><b></b>${_scriptEnd}`);
expect(DOM.getInnerHTML(parent))
.toEqual(`${_scriptStart}<a></a><b></b>${_scriptEnd}`);
});
it("should remove the nodes from the previous insertion", () => {

View File

@ -51,9 +51,9 @@ export function main() {
it('should rewrite style urls', () => {
var styleElement = el('<style>.foo {background-image: url("img.jpg");}</style>');
strategy.processStyleElement('someComponent', 'http://base', styleElement);
expect(styleElement).toHaveText(".foo[_ngcontent-0] {\n" +
"background-image: url(http://base/img.jpg);\n" +
"}");
expect(styleElement)
.toHaveText(".foo[_ngcontent-0] {\n" + "background-image: url(http://base/img.jpg);\n" +
"}");
});
it('should scope styles', () => {
@ -63,18 +63,19 @@ export function main() {
});
it('should inline @import rules', inject([AsyncTestCompleter], (async) => {
xhr.reply('http://base/one.css', '.one {}');
xhr.reply('http://base/one.css', '.one {}');
var styleElement = el('<style>@import "one.css";</style>');
var stylePromise = strategy.processStyleElement('someComponent', 'http://base', styleElement);
expect(stylePromise).toBePromise();
expect(styleElement).toHaveText('');
var styleElement = el('<style>@import "one.css";</style>');
var stylePromise =
strategy.processStyleElement('someComponent', 'http://base', styleElement);
expect(stylePromise).toBePromise();
expect(styleElement).toHaveText('');
stylePromise.then((_) => {
expect(styleElement).toHaveText('.one[_ngcontent-0] {\n\n}');
async.done();
});
}));
stylePromise.then((_) => {
expect(styleElement).toHaveText('.one[_ngcontent-0] {\n\n}');
async.done();
});
}));
it('should return the same style given the same component', () => {
var styleElement = el('<style>.foo {} :host {}</style>');
@ -121,7 +122,7 @@ export function main() {
}
class FakeXHR extends XHR {
_responses: Map;
_responses: Map<string, string>;
constructor() {
super();
@ -137,7 +138,5 @@ class FakeXHR extends XHR {
return PromiseWrapper.resolve(response);
}
reply(url: string, response: string) {
MapWrapper.set(this._responses, url, response);
}
reply(url: string, response: string) { MapWrapper.set(this._responses, url, response); }
}

View File

@ -46,13 +46,12 @@ export function main() {
it('should rewrite style urls', () => {
var styleElement = el('<style>.foo {background-image: url("img.jpg");}</style>');
strategy.processStyleElement('someComponent', 'http://base', styleElement);
expect(styleElement).toHaveText(".foo {" +
"background-image: url('http://base/img.jpg');" +
"}");
expect(styleElement)
.toHaveText(".foo {" + "background-image: url('http://base/img.jpg');" + "}");
});
it('should not inline import rules', () => {
var styleElement = el('<style>@import "other.css";</style>')
var styleElement = el('<style>@import "other.css";</style>');
strategy.processStyleElement('someComponent', 'http://base', styleElement);
expect(styleElement).toHaveText("@import 'http://base/other.css';");
});
@ -81,4 +80,3 @@ export function main() {
});
}

View File

@ -1,4 +1,14 @@
import {describe, beforeEach, it, expect, ddescribe, iit, SpyObject, el, proxy} from 'angular2/test_lib';
import {
describe,
beforeEach,
it,
expect,
ddescribe,
iit,
SpyObject,
el,
proxy
} from 'angular2/test_lib';
import {IMPLEMENTS, isBlank, isPresent} from 'angular2/src/facade/lang';
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter';
@ -9,12 +19,13 @@ import {DomViewContainer} from 'angular2/src/render/dom/view/view_container';
@proxy
@IMPLEMENTS(DomView)
class FakeView {
class FakeView extends SpyObject {
boundElements;
contentTags;
viewContainers;
constructor(containers = null) {
super(DomView);
this.boundElements = [];
this.contentTags = [];
this.viewContainers = [];
@ -38,62 +49,50 @@ class FakeView {
}
}
noSuchMethod(i) {
super.noSuchMethod(i);
}
noSuchMethod(i) { super.noSuchMethod(i); }
}
@proxy
@IMPLEMENTS(DomViewContainer)
class FakeViewContainer {
class FakeViewContainer extends SpyObject {
_nodes;
_contentTagContainers;
templateElement;
constructor(templateEl, nodes = null, views = null) {
super(DomViewContainer);
this.templateElement = templateEl;
this._nodes = nodes;
this._contentTagContainers = views;
}
nodes(){
return this._nodes;
}
nodes() { return this._nodes; }
contentTagContainers(){
return this._contentTagContainers;
}
contentTagContainers() { return this._contentTagContainers; }
noSuchMethod(i) {
super.noSuchMethod(i);
}
noSuchMethod(i) { super.noSuchMethod(i); }
}
@proxy
@IMPLEMENTS(Content)
class FakeContentTag {
class FakeContentTag extends SpyObject {
select;
_nodes;
contentStartElement;
constructor(contentEl, select = '', nodes = null) {
super(Content);
this.contentStartElement = contentEl;
this.select = select;
this._nodes = nodes;
}
insert(nodes){
this._nodes = nodes;
}
insert(nodes) { this._nodes = nodes; }
nodes() {
return this._nodes;
}
nodes() { return this._nodes; }
noSuchMethod(i) {
super.noSuchMethod(i);
}
noSuchMethod(i) { super.noSuchMethod(i); }
}
function createLightDom(hostView, shadowView, el) {
@ -106,29 +105,23 @@ export function main() {
describe('LightDom', function() {
var lightDomView;
beforeEach(() => {
lightDomView = new FakeView();
});
beforeEach(() => { lightDomView = new FakeView(); });
describe("contentTags", () => {
it("should collect content tags from element injectors", () => {
var tag = new FakeContentTag(el('<script></script>'));
var shadowDomView = new FakeView([tag]);
var lightDom = createLightDom(lightDomView, shadowDomView,
el("<div></div>"));
var lightDom = createLightDom(lightDomView, shadowDomView, el("<div></div>"));
expect(lightDom.contentTags()).toEqual([tag]);
});
it("should collect content tags from ViewContainers", () => {
var tag = new FakeContentTag(el('<script></script>'));
var vc = new FakeViewContainer(null, null, [
new FakeView([tag])
]);
var vc = new FakeViewContainer(null, null, [new FakeView([tag])]);
var shadowDomView = new FakeView([vc]);
var lightDom = createLightDom(lightDomView, shadowDomView,
el("<div></div>"));
var lightDom = createLightDom(lightDomView, shadowDomView, el("<div></div>"));
expect(lightDom.contentTags()).toEqual([tag]);
});
@ -136,7 +129,7 @@ export function main() {
describe("expandedDomNodes", () => {
it("should contain root nodes", () => {
var lightDomEl = el("<div><a></a></div>")
var lightDomEl = el("<div><a></a></div>");
var lightDom = createLightDom(lightDomView, new FakeView(), lightDomEl);
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["<a></a>"]);
});
@ -144,14 +137,11 @@ export function main() {
it("should include view container nodes", () => {
var lightDomEl = el("<div><template></template></div>");
var lightDom = createLightDom(
new FakeView([
new FakeViewContainer(
DOM.firstChild(lightDomEl), // template element
[el('<a></a>')] // light DOM nodes of view container
)
]),
null,
lightDomEl);
new FakeView(
[new FakeViewContainer(DOM.firstChild(lightDomEl), // template element
[el('<a></a>')] // light DOM nodes of view container
)]),
null, lightDomEl);
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["<a></a>"]);
});
@ -159,15 +149,11 @@ export function main() {
it("should include content nodes", () => {
var lightDomEl = el("<div><content></content></div>");
var lightDom = createLightDom(
new FakeView([
new FakeContentTag(
DOM.firstChild(lightDomEl), // content element
'', // selector
[el('<a></a>')] // light DOM nodes of content tag
)
]),
null,
lightDomEl);
new FakeView([new FakeContentTag(DOM.firstChild(lightDomEl), // content element
'', // selector
[el('<a></a>')] // light DOM nodes of content tag
)]),
null, lightDomEl);
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["<a></a>"]);
});
@ -175,12 +161,9 @@ export function main() {
it("should work when the element injector array contains nulls", () => {
var lightDomEl = el("<div><a></a></div>")
var lightDomView = new FakeView();
var lightDomView = new FakeView();
var lightDom = createLightDom(
lightDomView,
new FakeView(),
lightDomEl);
var lightDom = createLightDom(lightDomView, new FakeView(), lightDomEl);
expect(toHtml(lightDom.expandedDomNodes())).toEqual(["<a></a>"]);
});
@ -193,10 +176,8 @@ export function main() {
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>")
var lightDom = createLightDom(lightDomView, new FakeView([
contentA,
contentB
]), lightDomEl);
var lightDom =
createLightDom(lightDomView, new FakeView([contentA, contentB]), lightDomEl);
lightDom.redistribute();
@ -210,10 +191,8 @@ export function main() {
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>")
var lightDom = createLightDom(lightDomView, new FakeView([
wildcard,
contentB
]), lightDomEl);
var lightDom =
createLightDom(lightDomView, new FakeView([wildcard, contentB]), lightDomEl);
lightDom.redistribute();
@ -224,7 +203,7 @@ export function main() {
it("should remove all nodes if there are no content tags", () => {
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>")
var lightDom = createLightDom(lightDomView, new FakeView([]), lightDomEl);
var lightDom = createLightDom(lightDomView, new FakeView([]), lightDomEl);
lightDom.redistribute();
@ -235,9 +214,8 @@ export function main() {
var lightDomEl = el("<div><a>1</a><b>2</b><a>3</a></div>");
var bNode = DOM.childNodes(lightDomEl)[1];
var lightDom = createLightDom(lightDomView, new FakeView([
new FakeContentTag(null, "a")
]), lightDomEl);
var lightDom =
createLightDom(lightDomView, new FakeView([new FakeContentTag(null, "a")]), lightDomEl);
lightDom.redistribute();

View File

@ -40,13 +40,12 @@ export function main() {
it('should rewrite style urls', () => {
var styleElement = el('<style>.foo {background-image: url("img.jpg");}</style>');
strategy.processStyleElement('someComponent', 'http://base', styleElement);
expect(styleElement).toHaveText(".foo {" +
"background-image: url('http://base/img.jpg');" +
"}");
expect(styleElement)
.toHaveText(".foo {" + "background-image: url('http://base/img.jpg');" + "}");
});
it('should not inline import rules', () => {
var styleElement = el('<style>@import "other.css";</style>')
var styleElement = el('<style>@import "other.css";</style>');
strategy.processStyleElement('someComponent', 'http://base', styleElement);
expect(styleElement).toHaveText("@import 'http://base/other.css';");
});

View File

@ -6,16 +6,14 @@ import {RegExpWrapper, StringWrapper} from 'angular2/src/facade/lang';
export function main() {
describe('ShadowCss', function() {
function s(css: string, contentAttr:string, hostAttr:string = '') {
function s(css: string, contentAttr: string, hostAttr: string = '') {
var shadowCss = new ShadowCss();
var shim = shadowCss.shimCssText(css, contentAttr, hostAttr);
var nlRegexp = RegExpWrapper.create('\\n');
return StringWrapper.replaceAll(shim, nlRegexp, '');
}
it('should handle empty string', () => {
expect(s('', 'a')).toEqual('');
});
it('should handle empty string', () => { expect(s('', 'a')).toEqual(''); });
it('should add an attribute to every rule', () => {
var css = 'one {color: red;}two {color: red;}';
@ -67,12 +65,14 @@ export function main() {
it('should handle :host', () => {
expect(s(':host {}', 'a', 'a-host')).toEqual('[a-host] {}');
expect(s(':host(.x,.y) {}', 'a', 'a-host')).toEqual('[a-host].x, [a-host].y {}');
expect(s(':host(.x,.y) > .z {}', 'a', 'a-host')).toEqual('[a-host].x > .z, [a-host].y > .z {}');
expect(s(':host(.x,.y) > .z {}', 'a', 'a-host'))
.toEqual('[a-host].x > .z, [a-host].y > .z {}');
});
it('should handle :host-context', () => {
expect(s(':host-context(.x) {}', 'a', 'a-host')).toEqual('[a-host].x, .x [a-host] {}');
expect(s(':host-context(.x) > .y {}', 'a', 'a-host')).toEqual('[a-host].x > .y, .x [a-host] > .y {}');
expect(s(':host-context(.x) > .y {}', 'a', 'a-host'))
.toEqual('[a-host].x > .y, .x [a-host] > .y {}');
});
it('should support polyfill-next-selector', () => {

View File

@ -1,234 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
beforeEachBindings,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
} from 'angular2/test_lib';
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
import {isBlank} from 'angular2/src/facade/lang';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {XHR} from 'angular2/src/services/xhr';
import {bind} from 'angular2/di';
export function main() {
describe('StyleInliner', () => {
beforeEachBindings(() => [
bind(XHR).toClass(FakeXHR),
]);
describe('loading', () => {
it('should return a string when there is no import statement', inject([StyleInliner], (inliner) => {
var css = '.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toEqual(css);
}));
it('should inline @import rules',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import url("one.css");.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
it('should support url([unquoted url]) in @import rules',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import url(one.css);.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
it('should handle @import error gracefuly',
inject([StyleInliner, AsyncTestCompleter], (inliner, async) => {
var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('/* failed to import http://base/one.css */\n.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
it('should inline multiple @import rules',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
xhr.reply('http://base/two.css', '.two {}');
var css = '@import "one.css";@import "two.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.two {}\n.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
it('should inline nested @import rules',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
xhr.reply('http://base/two.css', '.two {}');
var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('.two {}\n.one {}\n.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
it('should handle circular dependencies gracefuly',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
xhr.reply('http://base/two.css', '@import "one.css";.two {}');
var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('.two {}\n.one {}\n.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
it('should handle invalid @import fracefuly',
inject([StyleInliner, AsyncTestCompleter], (inliner, async) => {
// Invalid rule: the url is not quoted
var css = '@import one.css;.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('/* Invalid import rule: "@import one.css;" */.main {}');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
});
describe('media query', () => {
it('should wrap inlined content in media query',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import "one.css" (min-width: 700px) and (orientation: landscape);';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('@media (min-width: 700px) and (orientation: landscape) {\n.one {}\n}\n');
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
});
describe('url rewritting', () => {
it('should rewrite url in inlined content',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
// it should rewrite both '@import' and 'url()'
xhr.reply('http://base/one.css', '@import "./nested/two.css";.one {background-image: url("one.jpg");}');
xhr.reply('http://base/nested/two.css', '.two {background-image: url("../img/two.jpg");}');
var css = '@import "one.css";'
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual(
".two {background-image: url('http://base/img/two.jpg');}\n" +
".one {background-image: url('http://base/one.jpg');}\n"
);
async.done();
},
function(e) {
throw 'fail;'
}
);
}));
});
});
}
class FakeXHR extends XHR {
_responses: Map;
constructor() {
super();
this._responses = MapWrapper.create();
}
get(url: string): Promise<string> {
var response = MapWrapper.get(this._responses, url);
if (isBlank(response)) {
return PromiseWrapper.reject('xhr error', null);
}
return PromiseWrapper.resolve(response);
}
reply(url: string, response: string) {
MapWrapper.set(this._responses, url, response);
}
}

View File

@ -0,0 +1,203 @@
import {
AsyncTestCompleter,
beforeEach,
beforeEachBindings,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
} from 'angular2/test_lib';
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
import {isBlank} from 'angular2/src/facade/lang';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {Map, MapWrapper} from 'angular2/src/facade/collection';
import {XHR} from 'angular2/src/services/xhr';
import {bind} from 'angular2/di';
export function main() {
describe('StyleInliner', () => {
beforeEachBindings(() => [
bind(XHR)
.toClass(FakeXHR),
]);
describe('loading', () => {
it('should return a string when there is no import statement',
inject([StyleInliner], (inliner) => {
var css = '.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toEqual(css);
}));
it('should inline @import rules',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import url("one.css");.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.main {}');
async.done();
},
function(e) { throw 'fail;' });
}));
it('should support url([unquoted url]) in @import rules',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import url(one.css);.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.main {}');
async.done();
},
function(e) { throw 'fail;' });
}));
it('should handle @import error gracefuly',
inject([StyleInliner, AsyncTestCompleter], (inliner, async) => {
var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('/* failed to import http://base/one.css */\n.main {}');
async.done();
},
function(e) { throw 'fail;' });
}));
it('should inline multiple @import rules',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
xhr.reply('http://base/two.css', '.two {}');
var css = '@import "one.css";@import "two.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise();
PromiseWrapper.then(loadedCss,
function(css) {
expect(css).toEqual('.one {}\n.two {}\n.main {}');
async.done();
},
function(e) { throw 'fail;' });
}));
it('should inline nested @import rules',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
xhr.reply('http://base/two.css', '.two {}');
var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(loadedCss,
function(css) {
expect(css).toEqual('.two {}\n.one {}\n.main {}');
async.done();
},
function(e) { throw 'fail;' });
}));
it('should handle circular dependencies gracefuly',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '@import "two.css";.one {}');
xhr.reply('http://base/two.css', '@import "one.css";.two {}');
var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(loadedCss,
function(css) {
expect(css).toEqual('.two {}\n.one {}\n.main {}');
async.done();
},
function(e) { throw 'fail;' });
}));
it('should handle invalid @import fracefuly',
inject([StyleInliner, AsyncTestCompleter], (inliner, async) => {
// Invalid rule: the url is not quoted
var css = '@import one.css;.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual('/* Invalid import rule: "@import one.css;" */.main {}');
async.done();
},
function(e) { throw 'fail;' });
}));
});
describe('media query', () => {
it('should wrap inlined content in media query',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
xhr.reply('http://base/one.css', '.one {}');
var css = '@import "one.css" (min-width: 700px) and (orientation: landscape);';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual(
'@media (min-width: 700px) and (orientation: landscape) {\n.one {}\n}\n');
async.done();
},
function(e) { throw 'fail;' });
}));
});
describe('url rewritting', () => {
it('should rewrite url in inlined content',
inject([XHR, StyleInliner, AsyncTestCompleter], (xhr, inliner, async) => {
// it should rewrite both '@import' and 'url()'
xhr.reply('http://base/one.css',
'@import "./nested/two.css";.one {background-image: url("one.jpg");}');
xhr.reply('http://base/nested/two.css',
'.two {background-image: url("../img/two.jpg");}');
var css = '@import "one.css";';
var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise();
PromiseWrapper.then(
loadedCss,
function(css) {
expect(css).toEqual(".two {background-image: url('http://base/img/two.jpg');}\n" +
".one {background-image: url('http://base/one.jpg');}\n");
async.done();
},
function(e) { throw 'fail;' });
}));
});
});
}
class FakeXHR extends XHR {
_responses: Map<string, string>;
constructor() {
super();
this._responses = MapWrapper.create();
}
get(url: string): Promise<string> {
var response = MapWrapper.get(this._responses, url);
if (isBlank(response)) {
return PromiseWrapper.reject('xhr error', null);
}
return PromiseWrapper.resolve(response);
}
reply(url: string, response: string) { MapWrapper.set(this._responses, url, response); }
}

View File

@ -74,7 +74,5 @@ export function main() {
}
class FakeUrlResolver extends UrlResolver {
resolve(baseUrl: string, url: string): string {
return baseUrl + '/' + url;
}
resolve(baseUrl: string, url: string): string { return baseUrl + '/' + url; }
}

View File

@ -1,507 +0,0 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
el,
elementText,
expect,
iit,
inject,
it,
xit,
beforeEachBindings,
SpyObject,
} from 'angular2/test_lib';
import {bind} from 'angular2/di';
import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {
ViewDefinition, DirectiveMetadata
} from 'angular2/src/render/api';
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
import {EmulatedScopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy';
import {EmulatedUnscopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
import {NativeShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
import {DomTestbed} from './dom_testbed';
export function main() {
describe('ShadowDom integration tests', function() {
var strategies = {
"scoped" : bind(ShadowDomStrategy).toFactory(
(styleInliner, styleUrlResolver) => new EmulatedScopedShadowDomStrategy(styleInliner, styleUrlResolver, null),
[StyleInliner, StyleUrlResolver]),
"unscoped" : bind(ShadowDomStrategy).toFactory(
(styleUrlResolver) => new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, null),
[StyleUrlResolver])
}
if (DOM.supportsNativeShadowDOM()) {
StringMapWrapper.set(strategies, "native", bind(ShadowDomStrategy).toFactory(
(styleUrlResolver) => new NativeShadowDomStrategy(styleUrlResolver),
[StyleUrlResolver])
);
}
StringMapWrapper.forEach(strategies,
(strategyBinding, name) => {
beforeEachBindings( () => {
return [strategyBinding, DomTestbed];
});
describe(`${name} shadow dom strategy`, () => {
it('should support simple components', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<simple>' +
'<div>A</div>' +
'</simple>',
directives: [simple]
}),
simpleTemplate
]).then( (protoViews) => {
tb.createRootViews(protoViews);
expect(tb.rootEl).toHaveText('SIMPLE(A)');
async.done();
});
}));
it('should not show the light dom even if there is not content tag', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<empty>' +
'<div>A</div>' +
'</empty>',
directives: [empty]
}),
emptyTemplate
]).then( (protoViews) => {
tb.createRootViews(protoViews);
expect(tb.rootEl).toHaveText('');
async.done();
});
}));
it('should support dynamic components', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<dynamic>' +
'<div>A</div>' +
'</dynamic>',
directives: [dynamicComponent]
}),
simpleTemplate
]).then( (protoViews) => {
var views = tb.createRootViews(ListWrapper.slice(protoViews, 0, 2));
tb.createComponentView(views[1].viewRef, 0, protoViews[2]);
expect(tb.rootEl).toHaveText('SIMPLE(A)');
async.done();
});
}));
it('should support multiple content tags', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<multiple-content-tags>' +
'<div>B</div>' +
'<div>C</div>' +
'<div class="left">A</div>' +
'</multiple-content-tags>',
directives: [multipleContentTagsComponent]
}),
multipleContentTagsTemplate
]).then( (protoViews) => {
tb.createRootViews(protoViews);
expect(tb.rootEl).toHaveText('(A, BC)');
async.done();
});
}));
it('should redistribute only direct children', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<multiple-content-tags>' +
'<div>B<div class="left">A</div></div>' +
'<div>C</div>' +
'</multiple-content-tags>',
directives: [multipleContentTagsComponent]
}),
multipleContentTagsTemplate
]).then( (protoViews) => {
tb.createRootViews(protoViews);
expect(tb.rootEl).toHaveText('(, BAC)');
async.done();
});
}));
it("should redistribute direct child viewcontainers when the light dom changes",
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<multiple-content-tags>' +
'<div><div template="manual" class="left">A</div></div>' +
'<div>B</div>' +
'</multiple-content-tags>',
directives: [multipleContentTagsComponent, manualViewportDirective]
}),
multipleContentTagsTemplate
]).then( (protoViews) => {
var views = tb.createRootViews(protoViews);
var childProtoView = protoViews[1].elementBinders[1].nestedProtoView;
expect(tb.rootEl).toHaveText('(, B)');
var childView = tb.createViewInContainer(views[1].viewRef, 1, 0, childProtoView);
expect(tb.rootEl).toHaveText('(, AB)');
tb.destroyViewInContainer(views[1].viewRef, 1, 0, childView.viewRef);
expect(tb.rootEl).toHaveText('(, B)');
async.done();
});
}));
it("should redistribute when the light dom changes",
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<multiple-content-tags>' +
'<div template="manual" class="left">A</div>' +
'<div>B</div>' +
'</multiple-content-tags>',
directives: [multipleContentTagsComponent, manualViewportDirective]
}),
multipleContentTagsTemplate
]).then( (protoViews) => {
var views = tb.createRootViews(protoViews);
var childProtoView = protoViews[1].elementBinders[1].nestedProtoView;
expect(tb.rootEl).toHaveText('(, B)');
var childView = tb.createViewInContainer(views[1].viewRef, 1, 0, childProtoView);
expect(tb.rootEl).toHaveText('(A, B)');
tb.destroyViewInContainer(views[1].viewRef, 1, 0, childView.viewRef);
expect(tb.rootEl).toHaveText('(, B)');
async.done();
});
}));
it("should support nested components", inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<outer-with-indirect-nested>' +
'<div>A</div>' +
'<div>B</div>' +
'</outer-with-indirect-nested>',
directives: [outerWithIndirectNestedComponent]
}),
outerWithIndirectNestedTemplate,
simpleTemplate
]).then( (protoViews) => {
tb.createRootViews(protoViews);
expect(tb.rootEl).toHaveText('OUTER(SIMPLE(AB))');
async.done();
});
}));
it("should support nesting with content being direct child of a nested component",
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<outer>' +
'<div template="manual" class="left">A</div>' +
'<div>B</div>' +
'<div>C</div>' +
'</outer>',
directives: [outerComponent, manualViewportDirective]
}),
outerTemplate,
innerTemplate,
innerInnerTemplate
]).then( (protoViews) => {
var views = tb.createRootViews(protoViews);
var childProtoView = protoViews[1].elementBinders[1].nestedProtoView;
expect(tb.rootEl).toHaveText('OUTER(INNER(INNERINNER(,BC)))');
tb.createViewInContainer(views[1].viewRef, 1, 0, childProtoView);
expect(tb.rootEl).toHaveText('OUTER(INNER(INNERINNER(A,BC)))');
async.done();
});
}));
it('should redistribute when the shadow dom changes', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<conditional-content>' +
'<div class="left">A</div>' +
'<div>B</div>' +
'<div>C</div>' +
'</conditional-content>',
directives: [conditionalContentComponent]
}),
conditionalContentTemplate
]).then( (protoViews) => {
var views = tb.createRootViews(protoViews);
var childProtoView = protoViews[2].elementBinders[0].nestedProtoView;
expect(tb.rootEl).toHaveText('(, ABC)');
var childView = tb.createViewInContainer(views[2].viewRef, 0, 0, childProtoView);
expect(tb.rootEl).toHaveText('(A, BC)');
tb.destroyViewInContainer(views[2].viewRef, 0, 0, childView.viewRef);
expect(tb.rootEl).toHaveText('(, ABC)');
async.done();
});
}));
it("should support tabs with view caching", inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template:
'(<tab><span>0</span></tab>'+
'<tab><span>1</span></tab>'+
'<tab><span>2</span></tab>)',
directives: [tabComponent]
}),
tabTemplate
]).then( (protoViews) => {
var views = tb.createRootViews(ListWrapper.slice(protoViews, 0, 2));
var tabProtoView = protoViews[2];
var tabChildProtoView = tabProtoView.elementBinders[0].nestedProtoView;
var tab1View = tb.createComponentView(views[1].viewRef, 0, tabProtoView);
var tab2View = tb.createComponentView(views[1].viewRef, 1, tabProtoView);
var tab3View = tb.createComponentView(views[1].viewRef, 2, tabProtoView);
expect(tb.rootEl).toHaveText('()');
var tabChildView = tb.createViewInContainer(tab1View.viewRef, 0, 0, tabChildProtoView);
expect(tb.rootEl).toHaveText('(TAB(0))');
tb.renderer.dehydrateView(tabChildView.viewRef);
tb.renderer.detachViewInContainer(tab1View.viewRef, 0, 0, tabChildView.viewRef);
tb.renderer.attachViewInContainer(tab2View.viewRef, 0, 0, tabChildView.viewRef);
tb.renderer.hydrateView(tabChildView.viewRef);
expect(tb.rootEl).toHaveText('(TAB(1))');
tb.renderer.dehydrateView(tabChildView.viewRef);
tb.renderer.detachViewInContainer(tab2View.viewRef, 0, 0, tabChildView.viewRef);
tb.renderer.attachViewInContainer(tab3View.viewRef, 0, 0, tabChildView.viewRef);
tb.renderer.hydrateView(tabChildView.viewRef);
expect(tb.rootEl).toHaveText('(TAB(2))');
async.done();
});
}));
//Implement once ElementRef support changing a class
//it("should redistribute when a class has been added or removed");
//it('should not lose focus', () => {
// var temp = `<simple>aaa<input type="text" id="focused-input" ng-class="{'aClass' : showClass}"> bbb</simple>`;
//
// compile(temp, (view, lc) => {
// var input = view.rootNodes[1];
// input.focus();
//
// expect(document.activeElement.id).toEqual("focused-input");
//
// // update class of input
//
// expect(document.activeElement.id).toEqual("focused-input");
// });
//});
});
});
});
}
var mainDir = new DirectiveMetadata({
selector: 'main',
id: 'main',
type: DirectiveMetadata.COMPONENT_TYPE
});
var simple = new DirectiveMetadata({
selector: 'simple',
id: 'simple',
type: DirectiveMetadata.COMPONENT_TYPE
});
var empty = new DirectiveMetadata({
selector: 'empty',
id: 'empty',
type: DirectiveMetadata.COMPONENT_TYPE
});
var dynamicComponent = new DirectiveMetadata({
selector: 'dynamic',
id: 'dynamic',
type: DirectiveMetadata.COMPONENT_TYPE
});
var multipleContentTagsComponent = new DirectiveMetadata({
selector: 'multiple-content-tags',
id: 'multiple-content-tags',
type: DirectiveMetadata.COMPONENT_TYPE
});
var manualViewportDirective = new DirectiveMetadata({
selector: '[manual]',
id: 'manual',
type: DirectiveMetadata.DIRECTIVE_TYPE
});
var outerWithIndirectNestedComponent = new DirectiveMetadata({
selector: 'outer-with-indirect-nested',
id: 'outer-with-indirect-nested',
type: DirectiveMetadata.COMPONENT_TYPE
});
var outerComponent = new DirectiveMetadata({
selector: 'outer',
id: 'outer',
type: DirectiveMetadata.COMPONENT_TYPE
});
var innerComponent = new DirectiveMetadata({
selector: 'inner',
id: 'inner',
type: DirectiveMetadata.COMPONENT_TYPE
});
var innerInnerComponent = new DirectiveMetadata({
selector: 'innerinner',
id: 'innerinner',
type: DirectiveMetadata.COMPONENT_TYPE
});
var conditionalContentComponent = new DirectiveMetadata({
selector: 'conditional-content',
id: 'conditional-content',
type: DirectiveMetadata.COMPONENT_TYPE
});
var autoViewportDirective = new DirectiveMetadata({
selector: '[auto]',
id: '[auto]',
type: DirectiveMetadata.DIRECTIVE_TYPE
});
var tabComponent = new DirectiveMetadata({
selector: 'tab',
id: 'tab',
type: DirectiveMetadata.COMPONENT_TYPE
});
var simpleTemplate = new ViewDefinition({
componentId: 'simple',
template: 'SIMPLE(<content></content>)',
directives: []
});
var emptyTemplate = new ViewDefinition({
componentId: 'empty',
template: '',
directives: []
});
var multipleContentTagsTemplate = new ViewDefinition({
componentId: 'multiple-content-tags',
template: '(<content select=".left"></content>, <content></content>)',
directives: []
});
var outerWithIndirectNestedTemplate = new ViewDefinition({
componentId: 'outer-with-indirect-nested',
template: 'OUTER(<simple><div><content></content></div></simple>)',
directives: [simple]
});
var outerTemplate = new ViewDefinition({
componentId: 'outer',
template: 'OUTER(<inner><content></content></inner>)',
directives: [innerComponent]
});
var innerTemplate = new ViewDefinition({
componentId: 'inner',
template: 'INNER(<innerinner><content></content></innerinner>)',
directives: [innerInnerComponent]
});
var innerInnerTemplate = new ViewDefinition({
componentId: 'innerinner',
template: 'INNERINNER(<content select=".left"></content>,<content></content>)',
directives: []
});
var conditionalContentTemplate = new ViewDefinition({
componentId: 'conditional-content',
template: '<div>(<div *auto="cond"><content select=".left"></content></div>, <content></content>)</div>',
directives: [autoViewportDirective]
});
var tabTemplate = new ViewDefinition({
componentId: 'tab',
template: '<div><div *auto="cond">TAB(<content></content>)</div></div>',
directives: [autoViewportDirective]
});

View File

@ -0,0 +1,495 @@
import {
AsyncTestCompleter,
beforeEach,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
beforeEachBindings,
SpyObject,
} from 'angular2/test_lib';
import {bind} from 'angular2/di';
import {MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter';
import {ViewDefinition, DirectiveMetadata} from 'angular2/src/render/api';
import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy';
import {
EmulatedScopedShadowDomStrategy
} from 'angular2/src/render/dom/shadow_dom/emulated_scoped_shadow_dom_strategy';
import {
EmulatedUnscopedShadowDomStrategy
} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
import {
NativeShadowDomStrategy
} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
import {DomTestbed} from './dom_testbed';
export function main() {
describe('ShadowDom integration tests', function() {
var strategies = {
"scoped":
bind(ShadowDomStrategy)
.toFactory((styleInliner, styleUrlResolver) => new EmulatedScopedShadowDomStrategy(
styleInliner, styleUrlResolver, null),
[StyleInliner, StyleUrlResolver]),
"unscoped": bind(ShadowDomStrategy)
.toFactory((styleUrlResolver) =>
new EmulatedUnscopedShadowDomStrategy(styleUrlResolver, null),
[StyleUrlResolver])
};
if (DOM.supportsNativeShadowDOM()) {
StringMapWrapper.set(
strategies, "native",
bind(ShadowDomStrategy)
.toFactory((styleUrlResolver) => new NativeShadowDomStrategy(styleUrlResolver),
[StyleUrlResolver]));
}
StringMapWrapper.forEach(strategies, (strategyBinding, name) => {
beforeEachBindings(() => { return [strategyBinding, DomTestbed]; });
describe(`${name} shadow dom strategy`, () => {
it('should support simple components',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<simple>' +
'<div>A</div>' +
'</simple>',
directives: [simple]
}),
simpleTemplate
])
.then((protoViews) => {
tb.createRootViews(protoViews);
expect(tb.rootEl).toHaveText('SIMPLE(A)');
async.done();
});
}));
it('should not show the light dom even if there is not content tag',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<empty>' +
'<div>A</div>' +
'</empty>',
directives: [empty]
}),
emptyTemplate
])
.then((protoViews) => {
tb.createRootViews(protoViews);
expect(tb.rootEl).toHaveText('');
async.done();
});
}));
it('should support dynamic components',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<dynamic>' +
'<div>A</div>' +
'</dynamic>',
directives: [dynamicComponent]
}),
simpleTemplate
])
.then((protoViews) => {
var views = tb.createRootViews(ListWrapper.slice(protoViews, 0, 2));
tb.createComponentView(views[1].viewRef, 0, protoViews[2]);
expect(tb.rootEl).toHaveText('SIMPLE(A)');
async.done();
});
}));
it('should support multiple content tags',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<multiple-content-tags>' +
'<div>B</div>' +
'<div>C</div>' +
'<div class="left">A</div>' +
'</multiple-content-tags>',
directives: [multipleContentTagsComponent]
}),
multipleContentTagsTemplate
])
.then((protoViews) => {
tb.createRootViews(protoViews);
expect(tb.rootEl).toHaveText('(A, BC)');
async.done();
});
}));
it('should redistribute only direct children',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<multiple-content-tags>' +
'<div>B<div class="left">A</div></div>' +
'<div>C</div>' +
'</multiple-content-tags>',
directives: [multipleContentTagsComponent]
}),
multipleContentTagsTemplate
])
.then((protoViews) => {
tb.createRootViews(protoViews);
expect(tb.rootEl).toHaveText('(, BAC)');
async.done();
});
}));
it("should redistribute direct child viewcontainers when the light dom changes",
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<multiple-content-tags>' +
'<div><div template="manual" class="left">A</div></div>' +
'<div>B</div>' +
'</multiple-content-tags>',
directives: [multipleContentTagsComponent, manualViewportDirective]
}),
multipleContentTagsTemplate
])
.then((protoViews) => {
var views = tb.createRootViews(protoViews);
var childProtoView = protoViews[1].elementBinders[1].nestedProtoView;
expect(tb.rootEl).toHaveText('(, B)');
var childView = tb.createViewInContainer(views[1].viewRef, 1, 0, childProtoView);
expect(tb.rootEl).toHaveText('(, AB)');
tb.destroyViewInContainer(views[1].viewRef, 1, 0, childView.viewRef);
expect(tb.rootEl).toHaveText('(, B)');
async.done();
});
}));
it("should redistribute when the light dom changes",
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<multiple-content-tags>' +
'<div template="manual" class="left">A</div>' +
'<div>B</div>' +
'</multiple-content-tags>',
directives: [multipleContentTagsComponent, manualViewportDirective]
}),
multipleContentTagsTemplate
])
.then((protoViews) => {
var views = tb.createRootViews(protoViews);
var childProtoView = protoViews[1].elementBinders[1].nestedProtoView;
expect(tb.rootEl).toHaveText('(, B)');
var childView = tb.createViewInContainer(views[1].viewRef, 1, 0, childProtoView);
expect(tb.rootEl).toHaveText('(A, B)');
tb.destroyViewInContainer(views[1].viewRef, 1, 0, childView.viewRef);
expect(tb.rootEl).toHaveText('(, B)');
async.done();
});
}));
it("should support nested components",
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<outer-with-indirect-nested>' +
'<div>A</div>' +
'<div>B</div>' +
'</outer-with-indirect-nested>',
directives: [outerWithIndirectNestedComponent]
}),
outerWithIndirectNestedTemplate,
simpleTemplate
])
.then((protoViews) => {
tb.createRootViews(protoViews);
expect(tb.rootEl).toHaveText('OUTER(SIMPLE(AB))');
async.done();
});
}));
it("should support nesting with content being direct child of a nested component",
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<outer>' +
'<div template="manual" class="left">A</div>' +
'<div>B</div>' +
'<div>C</div>' +
'</outer>',
directives: [outerComponent, manualViewportDirective]
}),
outerTemplate,
innerTemplate,
innerInnerTemplate
])
.then((protoViews) => {
var views = tb.createRootViews(protoViews);
var childProtoView = protoViews[1].elementBinders[1].nestedProtoView;
expect(tb.rootEl).toHaveText('OUTER(INNER(INNERINNER(,BC)))');
tb.createViewInContainer(views[1].viewRef, 1, 0, childProtoView);
expect(tb.rootEl).toHaveText('OUTER(INNER(INNERINNER(A,BC)))');
async.done();
});
}));
it('should redistribute when the shadow dom changes',
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '<conditional-content>' +
'<div class="left">A</div>' +
'<div>B</div>' +
'<div>C</div>' +
'</conditional-content>',
directives: [conditionalContentComponent]
}),
conditionalContentTemplate
])
.then((protoViews) => {
var views = tb.createRootViews(protoViews);
var childProtoView = protoViews[2].elementBinders[0].nestedProtoView;
expect(tb.rootEl).toHaveText('(, ABC)');
var childView = tb.createViewInContainer(views[2].viewRef, 0, 0, childProtoView);
expect(tb.rootEl).toHaveText('(A, BC)');
tb.destroyViewInContainer(views[2].viewRef, 0, 0, childView.viewRef);
expect(tb.rootEl).toHaveText('(, ABC)');
async.done();
});
}));
it("should support tabs with view caching",
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
tb.compileAll([
mainDir,
new ViewDefinition({
componentId: 'main',
template: '(<tab><span>0</span></tab>' +
'<tab><span>1</span></tab>' +
'<tab><span>2</span></tab>)',
directives: [tabComponent]
}),
tabTemplate
])
.then((protoViews) => {
var views = tb.createRootViews(ListWrapper.slice(protoViews, 0, 2));
var tabProtoView = protoViews[2];
var tabChildProtoView = tabProtoView.elementBinders[0].nestedProtoView;
var tab1View = tb.createComponentView(views[1].viewRef, 0, tabProtoView);
var tab2View = tb.createComponentView(views[1].viewRef, 1, tabProtoView);
var tab3View = tb.createComponentView(views[1].viewRef, 2, tabProtoView);
expect(tb.rootEl).toHaveText('()');
var tabChildView =
tb.createViewInContainer(tab1View.viewRef, 0, 0, tabChildProtoView);
expect(tb.rootEl).toHaveText('(TAB(0))');
tb.renderer.dehydrateView(tabChildView.viewRef);
tb.renderer.detachViewInContainer(tab1View.viewRef, 0, 0, tabChildView.viewRef);
tb.renderer.attachViewInContainer(tab2View.viewRef, 0, 0, tabChildView.viewRef);
tb.renderer.hydrateView(tabChildView.viewRef);
expect(tb.rootEl).toHaveText('(TAB(1))');
tb.renderer.dehydrateView(tabChildView.viewRef);
tb.renderer.detachViewInContainer(tab2View.viewRef, 0, 0, tabChildView.viewRef);
tb.renderer.attachViewInContainer(tab3View.viewRef, 0, 0, tabChildView.viewRef);
tb.renderer.hydrateView(tabChildView.viewRef);
expect(tb.rootEl).toHaveText('(TAB(2))');
async.done();
});
}));
// Implement once ElementRef support changing a class
// it("should redistribute when a class has been added or removed");
// it('should not lose focus', () => {
// var temp = `<simple>aaa<input type="text" id="focused-input" ng-class="{'aClass' :
// showClass}"> bbb</simple>`;
//
// compile(temp, (view, lc) => {
// var input = view.rootNodes[1];
// input.focus();
//
// expect(document.activeElement.id).toEqual("focused-input");
//
// // update class of input
//
// expect(document.activeElement.id).toEqual("focused-input");
// });
//});
});
});
});
}
var mainDir =
new DirectiveMetadata({selector: 'main', id: 'main', type: DirectiveMetadata.COMPONENT_TYPE});
var simple = new DirectiveMetadata(
{selector: 'simple', id: 'simple', type: DirectiveMetadata.COMPONENT_TYPE});
var empty = new DirectiveMetadata(
{selector: 'empty', id: 'empty', type: DirectiveMetadata.COMPONENT_TYPE});
var dynamicComponent = new DirectiveMetadata(
{selector: 'dynamic', id: 'dynamic', type: DirectiveMetadata.COMPONENT_TYPE});
var multipleContentTagsComponent = new DirectiveMetadata({
selector: 'multiple-content-tags',
id: 'multiple-content-tags',
type: DirectiveMetadata.COMPONENT_TYPE
});
var manualViewportDirective = new DirectiveMetadata(
{selector: '[manual]', id: 'manual', type: DirectiveMetadata.DIRECTIVE_TYPE});
var outerWithIndirectNestedComponent = new DirectiveMetadata({
selector: 'outer-with-indirect-nested',
id: 'outer-with-indirect-nested',
type: DirectiveMetadata.COMPONENT_TYPE
});
var outerComponent = new DirectiveMetadata(
{selector: 'outer', id: 'outer', type: DirectiveMetadata.COMPONENT_TYPE});
var innerComponent = new DirectiveMetadata(
{selector: 'inner', id: 'inner', type: DirectiveMetadata.COMPONENT_TYPE});
var innerInnerComponent = new DirectiveMetadata(
{selector: 'innerinner', id: 'innerinner', type: DirectiveMetadata.COMPONENT_TYPE});
var conditionalContentComponent = new DirectiveMetadata({
selector: 'conditional-content',
id: 'conditional-content',
type: DirectiveMetadata.COMPONENT_TYPE
});
var autoViewportDirective = new DirectiveMetadata(
{selector: '[auto]', id: '[auto]', type: DirectiveMetadata.DIRECTIVE_TYPE});
var tabComponent =
new DirectiveMetadata({selector: 'tab', id: 'tab', type: DirectiveMetadata.COMPONENT_TYPE});
var simpleTemplate = new ViewDefinition(
{componentId: 'simple', template: 'SIMPLE(<content></content>)', directives: []});
var emptyTemplate = new ViewDefinition({componentId: 'empty', template: '', directives: []});
var multipleContentTagsTemplate = new ViewDefinition({
componentId: 'multiple-content-tags',
template: '(<content select=".left"></content>, <content></content>)',
directives: []
});
var outerWithIndirectNestedTemplate = new ViewDefinition({
componentId: 'outer-with-indirect-nested',
template: 'OUTER(<simple><div><content></content></div></simple>)',
directives: [simple]
});
var outerTemplate = new ViewDefinition({
componentId: 'outer',
template: 'OUTER(<inner><content></content></inner>)',
directives: [innerComponent]
});
var innerTemplate = new ViewDefinition({
componentId: 'inner',
template: 'INNER(<innerinner><content></content></innerinner>)',
directives: [innerInnerComponent]
});
var innerInnerTemplate = new ViewDefinition({
componentId: 'innerinner',
template: 'INNERINNER(<content select=".left"></content>,<content></content>)',
directives: []
});
var conditionalContentTemplate = new ViewDefinition({
componentId: 'conditional-content',
template:
'<div>(<div *auto="cond"><content select=".left"></content></div>, <content></content>)</div>',
directives: [autoViewportDirective]
});
var tabTemplate = new ViewDefinition({
componentId: 'tab',
template: '<div><div *auto="cond">TAB(<content></content>)</div></div>',
directives: [autoViewportDirective]
});

View File

@ -1,12 +1,20 @@
import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, el} from 'angular2/test_lib';
import {
describe,
ddescribe,
it,
iit,
xit,
xdescribe,
expect,
beforeEach,
el
} from 'angular2/test_lib';
import {setterFactory} from 'angular2/src/render/dom/view/property_setter_factory';
import {DOM} from 'angular2/src/dom/dom_adapter';
export function main() {
var div;
beforeEach( () => {
div = el('<div></div>');
});
beforeEach(() => { div = el('<div></div>'); });
describe('property setter factory', () => {
it('should return a setter for a property', () => {
@ -24,9 +32,8 @@ export function main() {
expect(DOM.getAttribute(div, 'role')).toEqual('button');
setterFn(div, null);
expect(DOM.getAttribute(div, 'role')).toEqual(null);
expect(() => {
setterFn(div, 4);
}).toThrowError("Invalid role attribute, only string values are allowed, got '4'");
expect(() => { setterFn(div, 4); })
.toThrowError("Invalid role attribute, only string values are allowed, got '4'");
var otherSetterFn = setterFactory('attr.role');
expect(setterFn).toBe(otherSetterFn);

View File

@ -12,7 +12,8 @@ import {
beforeEachBindings,
it,
xit,
SpyObject, proxy
SpyObject,
proxy
} from 'angular2/test_lib';
import {IMPLEMENTS, isBlank} from 'angular2/src/facade/lang';
import {ListWrapper} from 'angular2/src/facade/collection';
@ -24,58 +25,48 @@ import {LightDom} from 'angular2/src/render/dom/shadow_dom/light_dom';
import {DOM} from 'angular2/src/dom/dom_adapter';
export function main() {
describe('DomView', () => {
function createProtoView(binders = null) {
if (isBlank(binders)) {
binders = [];
}
var rootEl = el('<div></div>');
return new DomProtoView({
element: rootEl,
elementBinders: binders
});
return new DomProtoView({element: rootEl, elementBinders: binders});
}
function createView(pv=null, boundElementCount=0) {
function createView(pv = null, boundElementCount = 0) {
if (isBlank(pv)) {
pv = createProtoView();
}
var root = el('<div><div></div></div>');
var boundElements = [];
for (var i=0; i<boundElementCount; i++) {
for (var i = 0; i < boundElementCount; i++) {
ListWrapper.push(boundElements, el('<span></span'));
}
return new DomView(pv, [DOM.childNodes(root)[0]],
[], boundElements, []);
return new DomView(pv, [DOM.childNodes(root)[0]], [], boundElements, []);
}
describe('getDirectParentLightDom', () => {
it('should return the LightDom of the direct parent', () => {
var pv = createProtoView(
[new ElementBinder(), new ElementBinder({
parentIndex: 0,
distanceToParent: 1
})]
);
[new ElementBinder(), new ElementBinder({parentIndex: 0, distanceToParent: 1})]);
var view = createView(pv, 2);
view.lightDoms[0] = new SpyLightDom();
view.lightDoms[1] = new SpyLightDom();
view.lightDoms[0] = <any>new SpyLightDom();
view.lightDoms[1] = <any>new SpyLightDom();
expect(view.getDirectParentLightDom(1)).toBe(view.lightDoms[0]);
});
it('should return null if the direct parent is not bound', () => {
var pv = createProtoView(
[new ElementBinder(), new ElementBinder(), new ElementBinder({
parentIndex: 0,
distanceToParent: 2
})]
);
var pv = createProtoView([
new ElementBinder(),
new ElementBinder(),
new ElementBinder({parentIndex: 0, distanceToParent: 2})
]);
var view = createView(pv, 3);
view.lightDoms[0] = new SpyLightDom();
view.lightDoms[1] = new SpyLightDom();
view.lightDoms[2] = new SpyLightDom();
view.lightDoms[0] = <any>new SpyLightDom();
view.lightDoms[1] = <any>new SpyLightDom();
view.lightDoms[2] = <any>new SpyLightDom();
expect(view.getDirectParentLightDom(2)).toBe(null);
});
@ -87,7 +78,6 @@ export function main() {
@proxy
@IMPLEMENTS(LightDom)
class SpyLightDom extends SpyObject {
constructor(){super(LightDom);}
noSuchMethod(m){return super.noSuchMethod(m)}
constructor() { super(LightDom); }
noSuchMethod(m) { return super.noSuchMethod(m) }
}