feat(view): add imperative views
This commit is contained in:
@ -10,10 +10,11 @@ import {
|
||||
inject,
|
||||
IS_DARTIUM,
|
||||
it,
|
||||
SpyObject, proxy
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {List, ListWrapper, Map, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {Type, isBlank, stringify, isPresent} from 'angular2/src/facade/lang';
|
||||
import {IMPLEMENTS, Type, isBlank, stringify, isPresent} from 'angular2/src/facade/lang';
|
||||
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||
|
||||
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
|
||||
@ -30,20 +31,28 @@ import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory';
|
||||
|
||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||
import * as renderApi from 'angular2/src/render/api';
|
||||
// TODO(tbosch): Spys don't support named modules...
|
||||
import {Renderer} from 'angular2/src/render/api';
|
||||
|
||||
export function main() {
|
||||
describe('compiler', function() {
|
||||
var reader, tplResolver, renderer, protoViewFactory, cmpUrlMapper;
|
||||
var reader, tplResolver, renderer, protoViewFactory, cmpUrlMapper, renderCompileRequests;
|
||||
|
||||
beforeEach(() => {
|
||||
reader = new DirectiveMetadataReader();
|
||||
tplResolver = new FakeTemplateResolver();
|
||||
cmpUrlMapper = new RuntimeComponentUrlMapper();
|
||||
renderer = new SpyRenderer();
|
||||
});
|
||||
|
||||
function createCompiler(renderCompileResults:List, protoViewFactoryResults:List<AppProtoView>) {
|
||||
var urlResolver = new FakeUrlResolver();
|
||||
renderer = new FakeRenderer(renderCompileResults);
|
||||
renderCompileRequests = [];
|
||||
renderer.spy('compile').andCallFake( (template) => {
|
||||
ListWrapper.push(renderCompileRequests, template);
|
||||
return PromiseWrapper.resolve(ListWrapper.removeAt(renderCompileResults, 0));
|
||||
});
|
||||
|
||||
protoViewFactory = new FakeProtoViewFactory(protoViewFactoryResults)
|
||||
return new Compiler(
|
||||
reader,
|
||||
@ -62,8 +71,8 @@ export function main() {
|
||||
tplResolver.setView(MainComponent, template);
|
||||
var compiler = createCompiler([createRenderProtoView()], [createProtoView()]);
|
||||
return compiler.compile(MainComponent).then( (protoView) => {
|
||||
expect(renderer.requests.length).toBe(1);
|
||||
return renderer.requests[0];
|
||||
expect(renderCompileRequests.length).toBe(1);
|
||||
return renderCompileRequests[0];
|
||||
});
|
||||
}
|
||||
|
||||
@ -362,6 +371,11 @@ export function main() {
|
||||
}));
|
||||
|
||||
it('should create host proto views', inject([AsyncTestCompleter], (async) => {
|
||||
renderer.spy('createHostProtoView').andCallFake( (componentId) => {
|
||||
return PromiseWrapper.resolve(
|
||||
createRenderProtoView([createRenderComponentElementBinder(0)])
|
||||
);
|
||||
});
|
||||
tplResolver.setView(MainComponent, new View({template: '<div></div>'}));
|
||||
var rootProtoView = createProtoView([
|
||||
createComponentElementBinder(reader, MainComponent)
|
||||
@ -379,6 +393,25 @@ export function main() {
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should create imperative proto views', inject([AsyncTestCompleter], (async) => {
|
||||
renderer.spy('createImperativeComponentProtoView').andCallFake( (rendererId) => {
|
||||
return PromiseWrapper.resolve(
|
||||
createRenderProtoView([])
|
||||
);
|
||||
});
|
||||
tplResolver.setView(MainComponent, new View({renderer: 'some-renderer'}));
|
||||
var mainProtoView = createProtoView();
|
||||
var compiler = createCompiler(
|
||||
[],
|
||||
[mainProtoView]
|
||||
);
|
||||
compiler.compile(MainComponent).then( (protoView) => {
|
||||
expect(protoView).toBe(mainProtoView);
|
||||
expect(renderer.spy('createImperativeComponentProtoView')).toHaveBeenCalledWith('some-renderer');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
@ -482,26 +515,11 @@ class DirectiveWithAttributes {
|
||||
constructor(@Attribute('someAttr') someAttr:string) {}
|
||||
}
|
||||
|
||||
class FakeRenderer extends renderApi.Renderer {
|
||||
requests:List<renderApi.ViewDefinition>;
|
||||
_results:List;
|
||||
|
||||
constructor(results) {
|
||||
super();
|
||||
this._results = results;
|
||||
this.requests = [];
|
||||
}
|
||||
|
||||
compile(template:renderApi.ViewDefinition):Promise<renderApi.ProtoViewDto> {
|
||||
ListWrapper.push(this.requests, template);
|
||||
return PromiseWrapper.resolve(ListWrapper.removeAt(this._results, 0));
|
||||
}
|
||||
|
||||
createHostProtoView(componentId):Promise<renderApi.ProtoViewDto> {
|
||||
return PromiseWrapper.resolve(
|
||||
createRenderProtoView([createRenderComponentElementBinder(0)])
|
||||
);
|
||||
}
|
||||
@proxy
|
||||
@IMPLEMENTS(Renderer)
|
||||
class SpyRenderer extends SpyObject {
|
||||
constructor(){super(Renderer);}
|
||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||
}
|
||||
|
||||
class FakeUrlResolver extends UrlResolver {
|
||||
|
@ -21,6 +21,7 @@ import {View} from 'angular2/src/core/annotations/view';
|
||||
import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader';
|
||||
import {ElementRef} from 'angular2/src/core/compiler/element_injector';
|
||||
import {If} from 'angular2/src/directives/if';
|
||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
|
||||
export function main() {
|
||||
describe('DynamicComponentLoader', function () {
|
||||
@ -134,9 +135,71 @@ export function main() {
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('loading into a new location', () => {
|
||||
it('should allow to create, update and destroy components',
|
||||
inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideView(MyComp, new View({
|
||||
template: '<imp-ng-cmp #impview></imp-ng-cmp>',
|
||||
directives: [ImperativeViewComponentUsingNgComponent]
|
||||
}));
|
||||
tb.createView(MyComp).then((view) => {
|
||||
var userViewComponent = view.rawView.locals.get("impview");
|
||||
|
||||
userViewComponent.done.then((childComponentRef) => {
|
||||
view.detectChanges();
|
||||
|
||||
expect(view.rootNodes).toHaveText('hello');
|
||||
|
||||
childComponentRef.instance.ctxProp = 'new';
|
||||
|
||||
view.detectChanges();
|
||||
|
||||
expect(view.rootNodes).toHaveText('new');
|
||||
|
||||
childComponentRef.dispose();
|
||||
|
||||
expect(view.rootNodes).toHaveText('');
|
||||
|
||||
async.done();
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'imp-ng-cmp'
|
||||
})
|
||||
@View({
|
||||
renderer: 'imp-ng-cmp-renderer'
|
||||
})
|
||||
class ImperativeViewComponentUsingNgComponent {
|
||||
done;
|
||||
|
||||
constructor(self:ElementRef, dynamicComponentLoader:DynamicComponentLoader, renderer:DirectDomRenderer) {
|
||||
var div = el('<div></div>');
|
||||
renderer.setImperativeComponentRootNodes(self.hostView.render, self.boundElementIndex, [div]);
|
||||
this.done = dynamicComponentLoader.loadIntoNewLocation(ChildComp, self, div, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'child-cmp',
|
||||
})
|
||||
@View({
|
||||
template: '{{ctxProp}}'
|
||||
})
|
||||
class ChildComp {
|
||||
ctxProp:string;
|
||||
constructor() {
|
||||
this.ctxProp = 'hello';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DynamicallyCreatedComponentService {
|
||||
}
|
||||
|
@ -714,7 +714,7 @@ export function main() {
|
||||
beforeEach( () => {
|
||||
renderer = new FakeRenderer();
|
||||
var protoView = new AppProtoView(null, null);
|
||||
view = new AppView(renderer, null, null, protoView, MapWrapper.create());
|
||||
view = new AppView(renderer, null, protoView, MapWrapper.create());
|
||||
view.render = new ViewRef();
|
||||
});
|
||||
|
||||
|
@ -33,6 +33,9 @@ import {If} from 'angular2/src/directives/if';
|
||||
|
||||
import {ViewContainer} from 'angular2/src/core/compiler/view_container';
|
||||
import {Compiler} from 'angular2/src/core/compiler/compiler';
|
||||
import {ElementRef} from 'angular2/src/core/compiler/element_injector';
|
||||
|
||||
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
|
||||
|
||||
export function main() {
|
||||
describe('integration tests', function() {
|
||||
@ -602,7 +605,7 @@ export function main() {
|
||||
DOM.dispatchEvent(view.rootNodes[1], DOM.createMouseEvent('click'));
|
||||
expect(DOM.getChecked(view.rootNodes[0])).toBeFalsy();
|
||||
expect(DOM.getChecked(view.rootNodes[1])).toBeTruthy();
|
||||
async.done();
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
@ -722,6 +725,18 @@ export function main() {
|
||||
}));
|
||||
});
|
||||
|
||||
it('should support imperative views',
|
||||
inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideView(MyComp, new View({
|
||||
template: '<simple-imp-cmp></simple-imp-cmp>',
|
||||
directives: [SimpleImperativeViewComponent]
|
||||
}));
|
||||
tb.createView(MyComp).then((view) => {
|
||||
expect(view.rootNodes).toHaveText('hello imp view');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
// Disabled until a solution is found, refs:
|
||||
// - https://github.com/angular/angular/issues/776
|
||||
// - https://github.com/angular/angular/commit/81f3f32
|
||||
@ -783,6 +798,21 @@ export function main() {
|
||||
});
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'simple-imp-cmp'
|
||||
})
|
||||
@View({
|
||||
renderer: 'simple-imp-cmp-renderer'
|
||||
})
|
||||
class SimpleImperativeViewComponent {
|
||||
done;
|
||||
|
||||
constructor(self:ElementRef, renderer:DirectDomRenderer) {
|
||||
renderer.setImperativeComponentRootNodes(self.hostView.render, self.boundElementIndex, [el('hello imp view')]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Decorator({
|
||||
selector: 'dynamic-vp'
|
||||
})
|
||||
@ -888,7 +918,7 @@ class ComponentWithPipes {
|
||||
|
||||
@Component({
|
||||
selector: 'child-cmp',
|
||||
injectables: [MyService]
|
||||
injectables: [MyService],
|
||||
})
|
||||
@View({
|
||||
directives: [MyDir],
|
||||
|
@ -35,7 +35,7 @@ export function main() {
|
||||
});
|
||||
|
||||
function createViewFactory({capacity}):ViewFactory {
|
||||
return new ViewFactory(capacity, renderer, null);
|
||||
return new ViewFactory(capacity, renderer);
|
||||
}
|
||||
|
||||
function createProtoChangeDetector() {
|
||||
|
@ -21,21 +21,24 @@ import {AppProtoView, AppView} from 'angular2/src/core/compiler/view';
|
||||
import {Renderer, ViewRef} from 'angular2/src/render/api';
|
||||
import {ChangeDetector} from 'angular2/change_detection';
|
||||
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
|
||||
import {DirectiveBinding, ElementInjector} from 'angular2/src/core/compiler/element_injector';
|
||||
import {DirectiveBinding, ElementInjector, ElementRef} from 'angular2/src/core/compiler/element_injector';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {Component} from 'angular2/src/core/annotations/annotations';
|
||||
import {AppViewHydrator} from 'angular2/src/core/compiler/view_hydrator';
|
||||
import {ViewFactory} from 'angular2/src/core/compiler/view_factory';
|
||||
|
||||
export function main() {
|
||||
describe('AppViewHydrator', () => {
|
||||
var renderer;
|
||||
var reader;
|
||||
var hydrator;
|
||||
var viewFactory;
|
||||
|
||||
beforeEach( () => {
|
||||
renderer = new SpyRenderer();
|
||||
reader = new DirectiveMetadataReader();
|
||||
hydrator = new AppViewHydrator(renderer);
|
||||
viewFactory = new SpyViewFactory();
|
||||
hydrator = new AppViewHydrator(renderer, viewFactory);
|
||||
});
|
||||
|
||||
function createDirectiveBinding(type) {
|
||||
@ -81,14 +84,14 @@ export function main() {
|
||||
}
|
||||
|
||||
function createEmptyView() {
|
||||
var view = new AppView(renderer, null, null, createProtoView(), MapWrapper.create());
|
||||
var view = new AppView(renderer, null, createProtoView(), MapWrapper.create());
|
||||
var changeDetector = new SpyChangeDetector();
|
||||
view.init(changeDetector, [], [], [], []);
|
||||
return view;
|
||||
}
|
||||
|
||||
function createHostView(pv, shadowView, componentInstance, elementInjectors = null) {
|
||||
var view = new AppView(renderer, null, null, pv, MapWrapper.create());
|
||||
var view = new AppView(renderer, null, pv, MapWrapper.create());
|
||||
var changeDetector = new SpyChangeDetector();
|
||||
|
||||
var eis;
|
||||
@ -117,7 +120,7 @@ export function main() {
|
||||
var view = createHostView(pv, null, null);
|
||||
var shadowView = createEmptyView();
|
||||
expect(
|
||||
() => hydrator.hydrateDynamicComponentView(view, 0, shadowView, null, null)
|
||||
() => hydrator.hydrateDynamicComponentView(new ElementRef(null, view, 0, null), shadowView, null, null)
|
||||
).toThrowError('There is no dynamic component directive at element 0');
|
||||
});
|
||||
|
||||
@ -126,7 +129,7 @@ export function main() {
|
||||
var view = createHostView(pv, null, null);
|
||||
var shadowView = createEmptyView();
|
||||
expect(
|
||||
() => hydrator.hydrateDynamicComponentView(view, 0, shadowView, null, null)
|
||||
() => hydrator.hydrateDynamicComponentView(new ElementRef(null, view, 0, null), shadowView, null, null)
|
||||
).toThrowError('There is no dynamic component directive at element 0');
|
||||
});
|
||||
|
||||
@ -135,9 +138,10 @@ export function main() {
|
||||
var shadowView = createEmptyView();
|
||||
var view = createHostView(pv, null, null);
|
||||
renderer.spy('createDynamicComponentView').andReturn([new ViewRef(), new ViewRef()]);
|
||||
hydrator.hydrateDynamicComponentView(view, 0, shadowView, createDirectiveBinding(SomeComponent), null);
|
||||
var elRef = new ElementRef(null, view, 0, null);
|
||||
hydrator.hydrateDynamicComponentView(elRef, shadowView, createDirectiveBinding(SomeComponent), null);
|
||||
expect(
|
||||
() => hydrator.hydrateDynamicComponentView(view, 0, shadowView, null, null)
|
||||
() => hydrator.hydrateDynamicComponentView(elRef, shadowView, null, null)
|
||||
).toThrowError('There already is a bound component at element 0');
|
||||
});
|
||||
|
||||
@ -217,6 +221,7 @@ export function main() {
|
||||
|
||||
expect(hostView.componentChildViews[0]).toBe(shadowView);
|
||||
expect(hostView.changeDetector.spy('removeShadowDomChild')).not.toHaveBeenCalled();
|
||||
expect(viewFactory.spy('returnView')).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should clear dynamic child components', () => {
|
||||
@ -225,6 +230,19 @@ export function main() {
|
||||
|
||||
expect(hostView.componentChildViews[0]).toBe(null);
|
||||
expect(hostView.changeDetector.spy('removeShadowDomChild')).toHaveBeenCalledWith(shadowView.changeDetector);
|
||||
expect(viewFactory.spy('returnView')).toHaveBeenCalledWith(shadowView);
|
||||
});
|
||||
|
||||
it('should clear imperatively added child components', () => {
|
||||
createAndHydrate(createProtoView());
|
||||
var impHostView = createHostView(createHostProtoView(createProtoView()), createEmptyView(), null);
|
||||
shadowView.imperativeHostViews = [impHostView];
|
||||
|
||||
dehydrate(hostView);
|
||||
|
||||
expect(shadowView.imperativeHostViews).toEqual([]);
|
||||
expect(viewFactory.spy('returnView')).toHaveBeenCalledWith(impHostView);
|
||||
expect(shadowView.changeDetector.spy('removeChild')).toHaveBeenCalledWith(impHostView.changeDetector);
|
||||
});
|
||||
|
||||
});
|
||||
@ -255,3 +273,10 @@ class SpyElementInjector extends SpyObject {
|
||||
constructor(){super(ElementInjector);}
|
||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||
}
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(ViewFactory)
|
||||
class SpyViewFactory extends SpyObject {
|
||||
constructor(){super(ViewFactory);}
|
||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||
}
|
@ -57,7 +57,7 @@ export function main() {
|
||||
}
|
||||
|
||||
function createViewWithOneBoundElement(pv) {
|
||||
var view = new AppView(renderer, null, null, pv, MapWrapper.create());
|
||||
var view = new AppView(renderer, null, pv, MapWrapper.create());
|
||||
var changeDetector = new SpyChangeDetector();
|
||||
var eij = createElementInjector();
|
||||
view.init(changeDetector, [eij], [eij],
|
||||
|
@ -50,6 +50,16 @@ export function main() {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should create imperative proto views', inject([AsyncTestCompleter], (async) => {
|
||||
createRenderer();
|
||||
renderer.createImperativeComponentProtoView('someRenderId').then( (rootProtoView) => {
|
||||
expect(rootProtoView.elementBinders).toEqual([]);
|
||||
|
||||
expect(rootProtoView.render.delegate.imperativeRendererId).toBe('someRenderId');
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should add a static component', inject([AsyncTestCompleter], (async) => {
|
||||
createRenderer();
|
||||
renderer.createHostProtoView('someComponentId').then( (rootProtoView) => {
|
||||
|
@ -46,7 +46,7 @@ export class IntegrationTestbed {
|
||||
this.eventPlugin = new FakeEventManagerPlugin();
|
||||
var eventManager = new EventManager([this.eventPlugin], new FakeVmTurnZone());
|
||||
var viewFactory = new ViewFactory(viewCacheCapacity, eventManager, shadowDomStrategy);
|
||||
var viewHydrator = new RenderViewHydrator(eventManager, viewFactory);
|
||||
var viewHydrator = new RenderViewHydrator(eventManager, viewFactory, shadowDomStrategy);
|
||||
this.renderer = new DirectDomRenderer(compiler, viewFactory, viewHydrator, shadowDomStrategy);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
xit,
|
||||
SpyObject, proxy
|
||||
} from 'angular2/test_lib';
|
||||
import {IMPLEMENTS, isBlank} from 'angular2/src/facade/lang';
|
||||
import {IMPLEMENTS, isBlank, isPresent} from 'angular2/src/facade/lang';
|
||||
|
||||
import {RenderProtoView} from 'angular2/src/render/dom/view/proto_view';
|
||||
import {ElementBinder} from 'angular2/src/render/dom/view/element_binder';
|
||||
@ -76,7 +76,7 @@ export function main() {
|
||||
function createHostView(pv, shadowDomView) {
|
||||
var view = new RenderView(pv, [el('<div></div>')],
|
||||
[], [el('<div></div>')], [null]);
|
||||
viewFactory.setComponentView(view, 0, shadowDomView);
|
||||
ViewFactory.setComponentView(shadowDomStrategy, view, 0, shadowDomView);
|
||||
return view;
|
||||
}
|
||||
|
||||
@ -94,8 +94,8 @@ export function main() {
|
||||
shadowDomStrategy.spy('constructLightDom').andCallFake( (lightDomView, shadowDomView, el) => {
|
||||
return new SpyLightDom();
|
||||
});
|
||||
viewFactory = new ViewFactory(1, eventManager, shadowDomStrategy);
|
||||
viewHydrator = new RenderViewHydrator(eventManager, viewFactory);
|
||||
viewFactory = new SpyViewFactory();
|
||||
viewHydrator = new RenderViewHydrator(eventManager, viewFactory, shadowDomStrategy);
|
||||
});
|
||||
|
||||
describe('hydrateDynamicComponentView', () => {
|
||||
@ -111,6 +111,59 @@ export function main() {
|
||||
|
||||
});
|
||||
|
||||
describe('hydrateInPlaceHostView', () => {
|
||||
|
||||
function createInPlaceHostView() {
|
||||
var hostPv = createHostProtoView(createProtoView());
|
||||
var shadowView = createEmptyView();
|
||||
return createHostView(hostPv, shadowView);
|
||||
}
|
||||
|
||||
it('should hydrate the view', () => {
|
||||
var hostView = createInPlaceHostView();
|
||||
viewHydrator.hydrateInPlaceHostView(null, hostView);
|
||||
|
||||
expect(hostView.hydrated).toBe(true);
|
||||
});
|
||||
|
||||
it('should store the view in the parent view', () => {
|
||||
var parentView = createEmptyView();
|
||||
var hostView = createInPlaceHostView();
|
||||
|
||||
viewHydrator.hydrateInPlaceHostView(parentView, hostView);
|
||||
|
||||
expect(parentView.imperativeHostViews).toEqual([hostView]);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('dehydrateInPlaceHostView', () => {
|
||||
|
||||
function createAndHydrateInPlaceHostView(parentView) {
|
||||
var hostPv = createHostProtoView(createProtoView());
|
||||
var shadowView = createEmptyView();
|
||||
var hostView = createHostView(hostPv, shadowView);
|
||||
viewHydrator.hydrateInPlaceHostView(parentView, hostView);
|
||||
return hostView;
|
||||
}
|
||||
|
||||
it('should clear the host view', () => {
|
||||
var parentView = createEmptyView();
|
||||
var hostView = createAndHydrateInPlaceHostView(parentView);
|
||||
|
||||
var rootNodes = hostView.rootNodes;
|
||||
expect(rootNodes[0].parentNode).toBeTruthy();
|
||||
|
||||
viewHydrator.dehydrateInPlaceHostView(parentView, hostView);
|
||||
|
||||
expect(parentView.imperativeHostViews).toEqual([]);
|
||||
expect(rootNodes[0].parentNode).toBeFalsy();
|
||||
expect(hostView.rootNodes).toEqual([]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('hydrate... shared functionality', () => {
|
||||
|
||||
it('should hydrate existing child components', () => {
|
||||
@ -128,9 +181,12 @@ export function main() {
|
||||
describe('dehydrate... shared functionality', () => {
|
||||
var hostView;
|
||||
|
||||
function createAndHydrate(nestedProtoView, shadowView) {
|
||||
function createAndHydrate(nestedProtoView, shadowView, imperativeHostView = null) {
|
||||
var hostPv = createHostProtoView(nestedProtoView);
|
||||
hostView = createHostView(hostPv, shadowView);
|
||||
if (isPresent(imperativeHostView)) {
|
||||
viewHydrator.hydrateInPlaceHostView(hostView, imperativeHostView);
|
||||
}
|
||||
|
||||
hydrate(hostView);
|
||||
}
|
||||
@ -152,15 +208,36 @@ export function main() {
|
||||
|
||||
expect(hostView.componentChildViews[0]).toBe(shadowView);
|
||||
expect(shadowView.rootNodes[0].parentNode).toBeTruthy();
|
||||
expect(viewFactory.spy('returnView')).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should clear dynamic child components', () => {
|
||||
var shadowView = createEmptyView();
|
||||
createAndHydrate(null, shadowView);
|
||||
expect(shadowView.rootNodes[0].parentNode).toBeTruthy();
|
||||
|
||||
dehydrate(hostView);
|
||||
|
||||
expect(hostView.componentChildViews[0]).toBe(null);
|
||||
expect(shadowView.rootNodes[0].parentNode).toBe(null);
|
||||
expect(viewFactory.spy('returnView')).toHaveBeenCalledWith(shadowView);
|
||||
});
|
||||
|
||||
it('should clear imperatively added child components', () => {
|
||||
var shadowView = createEmptyView();
|
||||
createAndHydrate(createProtoView(), shadowView);
|
||||
var impHostView = createHostView(createHostProtoView(createProtoView()), createEmptyView());
|
||||
shadowView.imperativeHostViews = [impHostView];
|
||||
|
||||
var rootNodes = impHostView.rootNodes;
|
||||
expect(rootNodes[0].parentNode).toBeTruthy();
|
||||
|
||||
dehydrate(hostView);
|
||||
|
||||
expect(shadowView.imperativeHostViews).toEqual([]);
|
||||
expect(impHostView.rootNodes).toEqual([]);
|
||||
expect(rootNodes[0].parentNode).toBeFalsy();
|
||||
expect(viewFactory.spy('returnView')).toHaveBeenCalledWith(impHostView);
|
||||
});
|
||||
|
||||
});
|
||||
@ -189,3 +266,9 @@ class SpyLightDom extends SpyObject {
|
||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||
}
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(ViewFactory)
|
||||
class SpyViewFactory extends SpyObject {
|
||||
constructor(){super(ViewFactory);}
|
||||
noSuchMethod(m){return super.noSuchMethod(m)}
|
||||
}
|
||||
|
Reference in New Issue
Block a user