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 {DomTestbed, elRef} from './dom_testbed'; export function main() { describe('ShadowDom integration tests', function() { var styleHost = DOM.createElement('div'); var strategies = { "scoped": bind(ShadowDomStrategy).toValue(new EmulatedScopedShadowDomStrategy(styleHost)), "unscoped": bind(ShadowDomStrategy).toValue(new EmulatedUnscopedShadowDomStrategy(styleHost)) }; if (DOM.supportsNativeShadowDOM()) { StringMapWrapper.set(strategies, "native", bind(ShadowDomStrategy).toValue(new NativeShadowDomStrategy())); } StringMapWrapper.forEach(strategies, (strategyBinding, name) => { describe(`${name} shadow dom strategy`, () => { beforeEachBindings(() => { return [strategyBinding, DomTestbed]; }); // GH-2095 - https://github.com/angular/angular/issues/2095 // important as we are adding a content end element during compilation, // which could skrew up text node indices. it('should support text nodes after content tags', inject([DomTestbed, AsyncTestCompleter], (tb, async) => { tb.compileAll([ simple, new ViewDefinition({ componentId: 'simple', template: '

P,

{{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, 'text'); expect(tb.rootEl).toHaveText('P,text'); async.done(); }); })); // important as we are moving style tags around during compilation, // which could skrew up text node indices. it('should support text nodes after style tags', inject([DomTestbed, AsyncTestCompleter], (tb, async) => { tb.compileAll([ simple, new ViewDefinition({ componentId: 'simple', template: '

P,

{{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, 'text'); expect(tb.rootEl).toHaveText('P,text'); async.done(); }); })); it('should support simple components', inject([AsyncTestCompleter, DomTestbed], (async, tb) => { tb.compileAll([ mainDir, new ViewDefinition({ componentId: 'main', template: '' + '
A
' + '
', directives: [simple] }), simpleTemplate ]) .then((protoViews) => { tb.createRootViews(protoViews); expect(tb.rootEl).toHaveText('SIMPLE(A)'); async.done(); }); })); it('should support simple components with text interpolation as direct children', inject([AsyncTestCompleter, DomTestbed], (async, tb) => { tb.compileAll([ mainDir, new ViewDefinition({ componentId: 'main', template: '' + '{{text}}' + '', directives: [simple] }), simpleTemplate ]) .then((protoViews) => { var cmpView = tb.createRootViews(protoViews)[1]; tb.renderer.setText(cmpView.viewRef, 0, 'A'); 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: '' + '
A
' + '
', 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: '' + '
A
' + '
', 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: '' + '
B
' + '
C
' + '
A
' + '
', 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: '' + '
B
A
' + '
C
' + '
', 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: '' + '
A
' + '
B
' + '
', 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: '' + '
A
' + '
B
' + '
', 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: '' + '
A
' + '
B
' + '
', 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: '' + '
A
' + '
B
' + '
C
' + '
', 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: '' + '
A
' + '
B
' + '
C
' + '
', 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: '(0' + '1' + '2)', 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(elRef(tab1View.viewRef, 0), 0, tabChildView.viewRef); tb.renderer.attachViewInContainer(elRef(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(elRef(tab2View.viewRef, 0), 0, tabChildView.viewRef); tb.renderer.attachViewInContainer(elRef(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 = `aaa bbb`; // // 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 = DirectiveMetadata.create( {selector: 'main', id: 'main', type: DirectiveMetadata.COMPONENT_TYPE}); var simple = DirectiveMetadata.create( {selector: 'simple', id: 'simple', type: DirectiveMetadata.COMPONENT_TYPE}); var empty = DirectiveMetadata.create( {selector: 'empty', id: 'empty', type: DirectiveMetadata.COMPONENT_TYPE}); var dynamicComponent = DirectiveMetadata.create( {selector: 'dynamic', id: 'dynamic', type: DirectiveMetadata.COMPONENT_TYPE}); var multipleContentTagsComponent = DirectiveMetadata.create({ selector: 'multiple-content-tags', id: 'multiple-content-tags', type: DirectiveMetadata.COMPONENT_TYPE }); var manualViewportDirective = DirectiveMetadata.create( {selector: '[manual]', id: 'manual', type: DirectiveMetadata.DIRECTIVE_TYPE}); var outerWithIndirectNestedComponent = DirectiveMetadata.create({ selector: 'outer-with-indirect-nested', id: 'outer-with-indirect-nested', type: DirectiveMetadata.COMPONENT_TYPE }); var outerComponent = DirectiveMetadata.create( {selector: 'outer', id: 'outer', type: DirectiveMetadata.COMPONENT_TYPE}); var innerComponent = DirectiveMetadata.create( {selector: 'inner', id: 'inner', type: DirectiveMetadata.COMPONENT_TYPE}); var innerInnerComponent = DirectiveMetadata.create( {selector: 'innerinner', id: 'innerinner', type: DirectiveMetadata.COMPONENT_TYPE}); var conditionalContentComponent = DirectiveMetadata.create({ selector: 'conditional-content', id: 'conditional-content', type: DirectiveMetadata.COMPONENT_TYPE }); var autoViewportDirective = DirectiveMetadata.create( {selector: '[auto]', id: 'auto', properties: ['auto'], type: DirectiveMetadata.DIRECTIVE_TYPE}); var tabComponent = DirectiveMetadata.create({selector: 'tab', id: 'tab', type: DirectiveMetadata.COMPONENT_TYPE}); var simpleTemplate = new ViewDefinition( {componentId: 'simple', template: 'SIMPLE()', directives: []}); var emptyTemplate = new ViewDefinition({componentId: 'empty', template: '', directives: []}); var multipleContentTagsTemplate = new ViewDefinition({ componentId: 'multiple-content-tags', template: '(, )', directives: [] }); var outerWithIndirectNestedTemplate = new ViewDefinition({ componentId: 'outer-with-indirect-nested', template: 'OUTER(
)', directives: [simple] }); var outerTemplate = new ViewDefinition({ componentId: 'outer', template: 'OUTER()', directives: [innerComponent] }); var innerTemplate = new ViewDefinition({ componentId: 'inner', template: 'INNER()', directives: [innerInnerComponent] }); var innerInnerTemplate = new ViewDefinition({ componentId: 'innerinner', template: 'INNERINNER(,)', directives: [] }); var conditionalContentTemplate = new ViewDefinition({ componentId: 'conditional-content', template: '
(
, )
', directives: [autoViewportDirective] }); var tabTemplate = new ViewDefinition({ componentId: 'tab', template: '
TAB()
', directives: [autoViewportDirective] });