feat(core): add query support to view engine
Part of #14013 closes #14084
This commit is contained in:

committed by
Victor Berchet

parent
fc8694ed11
commit
1e729d7ba2
@ -48,21 +48,21 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
describe('create', () => {
|
||||
it('should create anchor nodes without parents', () => {
|
||||
const rootNodes =
|
||||
createAndGetRootNodes(compViewDef([anchorDef(NodeFlags.None, 0)])).rootNodes;
|
||||
createAndGetRootNodes(compViewDef([anchorDef(NodeFlags.None, null, 0)])).rootNodes;
|
||||
expect(rootNodes.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should create views with multiple root anchor nodes', () => {
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||
anchorDef(NodeFlags.None, 0), anchorDef(NodeFlags.None, 0)
|
||||
anchorDef(NodeFlags.None, null, 0), anchorDef(NodeFlags.None, null, 0)
|
||||
])).rootNodes;
|
||||
expect(rootNodes.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should create anchor nodes with parents', () => {
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
anchorDef(NodeFlags.None, 0),
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
anchorDef(NodeFlags.None, null, 0),
|
||||
])).rootNodes;
|
||||
expect(getDOM().childNodes(rootNodes[0]).length).toBe(1);
|
||||
});
|
||||
|
@ -52,10 +52,12 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
}
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
providerDef(NodeFlags.None, AComp, [], null, null, () => compViewDef([
|
||||
elementDef(NodeFlags.None, 0, 'span'),
|
||||
])),
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
providerDef(
|
||||
NodeFlags.None, null, AComp, [], null, null, null,
|
||||
() => compViewDef([
|
||||
elementDef(NodeFlags.None, null, 0, 'span'),
|
||||
])),
|
||||
]));
|
||||
|
||||
const compView = view.nodes[1].provider.componentView;
|
||||
@ -78,10 +80,10 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
providerDef(NodeFlags.None, AComp, [], null, null, () => compViewDef(
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
providerDef(NodeFlags.None, null, AComp, [], null, null, null, () => compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, 0, 'span', null, [[BindingType.ElementAttribute, 'a', SecurityContext.NONE]]),
|
||||
elementDef(NodeFlags.None, null, 0, 'span', null, [[BindingType.ElementAttribute, 'a', SecurityContext.NONE]]),
|
||||
], update
|
||||
)),
|
||||
], jasmine.createSpy('parentUpdater')));
|
||||
@ -114,12 +116,12 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
}
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
providerDef(
|
||||
NodeFlags.None, AComp, [], null, null,
|
||||
NodeFlags.None, null, AComp, [], null, null, null,
|
||||
() => compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.OnDestroy, ChildProvider, [])
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.OnDestroy, null, ChildProvider, [])
|
||||
])),
|
||||
]));
|
||||
|
||||
|
@ -47,24 +47,25 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
describe('create', () => {
|
||||
it('should create elements without parents', () => {
|
||||
const rootNodes =
|
||||
createAndGetRootNodes(compViewDef([elementDef(NodeFlags.None, 0, 'span')])).rootNodes;
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 0, 'span')
|
||||
])).rootNodes;
|
||||
expect(rootNodes.length).toBe(1);
|
||||
expect(getDOM().nodeName(rootNodes[0]).toLowerCase()).toBe('span');
|
||||
});
|
||||
|
||||
it('should create views with multiple root elements', () => {
|
||||
const rootNodes =
|
||||
createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 0, 'span'), elementDef(NodeFlags.None, 0, 'span')
|
||||
])).rootNodes;
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 0, 'span'),
|
||||
elementDef(NodeFlags.None, null, 0, 'span')
|
||||
])).rootNodes;
|
||||
expect(rootNodes.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should create elements with parents', () => {
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
elementDef(NodeFlags.None, 0, 'span'),
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
elementDef(NodeFlags.None, null, 0, 'span'),
|
||||
])).rootNodes;
|
||||
expect(rootNodes.length).toBe(1);
|
||||
const spanEl = getDOM().childNodes(rootNodes[0])[0];
|
||||
@ -73,7 +74,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
it('should set fixed attributes', () => {
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 0, 'div', {'title': 'a'}),
|
||||
elementDef(NodeFlags.None, null, 0, 'div', {'title': 'a'}),
|
||||
])).rootNodes;
|
||||
expect(rootNodes.length).toBe(1);
|
||||
expect(getDOM().getAttribute(rootNodes[0], 'title')).toBe('a');
|
||||
@ -85,7 +86,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(
|
||||
NodeFlags.None, 0, 'div', null,
|
||||
NodeFlags.None, null, 0, 'div', null,
|
||||
[[BindingType.ElementAttribute, 'a1', SecurityContext.NONE]]),
|
||||
],
|
||||
(updater, view) => updater.checkInline(view, 0, attrValue)));
|
||||
@ -114,7 +115,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(
|
||||
NodeFlags.None, 0, 'input', null,
|
||||
NodeFlags.None, null, 0, 'input', null,
|
||||
[
|
||||
[BindingType.ElementProperty, 'title', SecurityContext.NONE],
|
||||
[BindingType.ElementProperty, 'value', SecurityContext.NONE]
|
||||
@ -145,7 +146,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(
|
||||
NodeFlags.None, 0, 'div', null,
|
||||
NodeFlags.None, null, 0, 'div', null,
|
||||
[
|
||||
[BindingType.ElementAttribute, 'a1', SecurityContext.NONE],
|
||||
[BindingType.ElementAttribute, 'a2', SecurityContext.NONE]
|
||||
@ -176,7 +177,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(
|
||||
NodeFlags.None, 0, 'div', null,
|
||||
NodeFlags.None, null, 0, 'div', null,
|
||||
[[BindingType.ElementClass, 'c1'], [BindingType.ElementClass, 'c2']]),
|
||||
],
|
||||
config.updater));
|
||||
@ -204,7 +205,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(
|
||||
NodeFlags.None, 0, 'div', null,
|
||||
NodeFlags.None, null, 0, 'div', null,
|
||||
[
|
||||
[BindingType.ElementStyle, 'width', 'px'],
|
||||
[BindingType.ElementStyle, 'color', null]
|
||||
@ -250,7 +251,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
const removeListenerSpy =
|
||||
spyOn(HTMLElement.prototype, 'removeEventListener').and.callThrough();
|
||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
|
||||
[elementDef(NodeFlags.None, 0, 'button', null, null, ['click'])], null,
|
||||
[elementDef(NodeFlags.None, null, 0, 'button', null, null, ['click'])], null,
|
||||
handleEventSpy));
|
||||
|
||||
rootNodes[0].click();
|
||||
@ -272,7 +273,8 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
const addListenerSpy = spyOn(window, 'addEventListener');
|
||||
const removeListenerSpy = spyOn(window, 'removeEventListener');
|
||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
|
||||
[elementDef(NodeFlags.None, 0, 'button', null, null, [['window', 'windowClick']])],
|
||||
[elementDef(
|
||||
NodeFlags.None, null, 0, 'button', null, null, [['window', 'windowClick']])],
|
||||
null, handleEventSpy));
|
||||
|
||||
expect(addListenerSpy).toHaveBeenCalled();
|
||||
@ -297,7 +299,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
const removeListenerSpy = spyOn(document, 'removeEventListener');
|
||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
|
||||
[elementDef(
|
||||
NodeFlags.None, 0, 'button', null, null, [['document', 'documentClick']])],
|
||||
NodeFlags.None, null, 0, 'button', null, null, [['document', 'documentClick']])],
|
||||
null, handleEventSpy));
|
||||
|
||||
expect(addListenerSpy).toHaveBeenCalled();
|
||||
@ -321,7 +323,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
let preventDefaultSpy: jasmine.Spy;
|
||||
|
||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
|
||||
[elementDef(NodeFlags.None, 0, 'button', null, null, ['click'])], null,
|
||||
[elementDef(NodeFlags.None, null, 0, 'button', null, null, ['click'])], null,
|
||||
(view, index, eventName, event) => {
|
||||
preventDefaultSpy = spyOn(event, 'preventDefault').and.callThrough();
|
||||
return eventHandlerResult;
|
||||
|
@ -56,9 +56,9 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
const {view: parentView, rootNodes} = createAndGetRootNodes(
|
||||
compViewDef([
|
||||
elementDef(NodeFlags.None, 2, 'div'),
|
||||
anchorDef(NodeFlags.HasEmbeddedViews, 0, embeddedViewDef([elementDef(
|
||||
NodeFlags.None, 0, 'span')])),
|
||||
elementDef(NodeFlags.None, null, 2, 'div'),
|
||||
anchorDef(NodeFlags.HasEmbeddedViews, null, 0, embeddedViewDef([elementDef(
|
||||
NodeFlags.None, null, 0, 'span')])),
|
||||
]),
|
||||
parentContext);
|
||||
|
||||
@ -69,12 +69,13 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
it('should attach and detach embedded views', () => {
|
||||
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 2, 'div'),
|
||||
elementDef(NodeFlags.None, null, 2, 'div'),
|
||||
anchorDef(
|
||||
NodeFlags.HasEmbeddedViews, 0,
|
||||
embeddedViewDef([elementDef(NodeFlags.None, 0, 'span', {'name': 'child0'})])),
|
||||
anchorDef(NodeFlags.None, 0, embeddedViewDef([elementDef(
|
||||
NodeFlags.None, 0, 'span', {'name': 'child1'})]))
|
||||
NodeFlags.HasEmbeddedViews, null, 0,
|
||||
embeddedViewDef([elementDef(NodeFlags.None, null, 0, 'span', {'name': 'child0'})])),
|
||||
anchorDef(
|
||||
NodeFlags.None, null, 0,
|
||||
embeddedViewDef([elementDef(NodeFlags.None, null, 0, 'span', {'name': 'child1'})]))
|
||||
]));
|
||||
|
||||
const childView0 = createEmbeddedView(parentView, parentView.def.nodes[1]);
|
||||
@ -99,9 +100,9 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
it('should include embedded views in root nodes', () => {
|
||||
const {view: parentView} = createAndGetRootNodes(compViewDef([
|
||||
anchorDef(
|
||||
NodeFlags.HasEmbeddedViews, 0,
|
||||
embeddedViewDef([elementDef(NodeFlags.None, 0, 'span', {'name': 'child0'})])),
|
||||
elementDef(NodeFlags.None, 0, 'span', {'name': 'after'})
|
||||
NodeFlags.HasEmbeddedViews, null, 0,
|
||||
embeddedViewDef([elementDef(NodeFlags.None, null, 0, 'span', {'name': 'child0'})])),
|
||||
elementDef(NodeFlags.None, null, 0, 'span', {'name': 'after'})
|
||||
]));
|
||||
|
||||
const childView0 = createEmbeddedView(parentView, parentView.def.nodes[0]);
|
||||
@ -119,12 +120,12 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
(updater: NodeUpdater, view: ViewData) => updater.checkInline(view, 0, childValue));
|
||||
|
||||
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
anchorDef(
|
||||
NodeFlags.HasEmbeddedViews, 0,
|
||||
NodeFlags.HasEmbeddedViews, null, 0,
|
||||
embeddedViewDef(
|
||||
[elementDef(
|
||||
NodeFlags.None, 0, 'span', null,
|
||||
NodeFlags.None, null, 0, 'span', null,
|
||||
[[BindingType.ElementAttribute, 'name', SecurityContext.NONE]])],
|
||||
update))
|
||||
]));
|
||||
@ -159,10 +160,10 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
}
|
||||
|
||||
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
anchorDef(NodeFlags.HasEmbeddedViews, 0, embeddedViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.OnDestroy, ChildProvider, [])
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
anchorDef(NodeFlags.HasEmbeddedViews, null, 0, embeddedViewDef([
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.OnDestroy, null, ChildProvider, [])
|
||||
]))
|
||||
]));
|
||||
|
||||
|
@ -56,8 +56,10 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
constructor() { instances.push(this); }
|
||||
}
|
||||
|
||||
createAndGetRootNodes(compViewDef(
|
||||
[elementDef(NodeFlags.None, 1, 'span'), providerDef(NodeFlags.None, SomeService, [])]));
|
||||
createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, null, SomeService, [])
|
||||
]));
|
||||
|
||||
expect(instances.length).toBe(1);
|
||||
});
|
||||
@ -74,8 +76,8 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
it('should inject deps from the same element', () => {
|
||||
createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 2, 'span'), providerDef(NodeFlags.None, Dep, []),
|
||||
providerDef(NodeFlags.None, SomeService, [Dep])
|
||||
elementDef(NodeFlags.None, null, 2, 'span'), providerDef(NodeFlags.None, null, Dep, []),
|
||||
providerDef(NodeFlags.None, null, SomeService, [Dep])
|
||||
]));
|
||||
|
||||
expect(instance.dep instanceof Dep).toBeTruthy();
|
||||
@ -83,8 +85,9 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
it('should inject deps from a parent element', () => {
|
||||
createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 3, 'span'), providerDef(NodeFlags.None, Dep, []),
|
||||
elementDef(NodeFlags.None, 1, 'span'), providerDef(NodeFlags.None, SomeService, [Dep])
|
||||
elementDef(NodeFlags.None, null, 3, 'span'), providerDef(NodeFlags.None, null, Dep, []),
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, null, SomeService, [Dep])
|
||||
]));
|
||||
|
||||
expect(instance.dep instanceof Dep).toBeTruthy();
|
||||
@ -92,8 +95,9 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
it('should not inject deps from sibling root elements', () => {
|
||||
const nodes = [
|
||||
elementDef(NodeFlags.None, 1, 'span'), providerDef(NodeFlags.None, Dep, []),
|
||||
elementDef(NodeFlags.None, 1, 'span'), providerDef(NodeFlags.None, SomeService, [Dep])
|
||||
elementDef(NodeFlags.None, null, 1, 'span'), providerDef(NodeFlags.None, null, Dep, []),
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, null, SomeService, [Dep])
|
||||
];
|
||||
|
||||
// root elements
|
||||
@ -103,18 +107,18 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
// non root elements
|
||||
expect(
|
||||
() => createAndGetRootNodes(
|
||||
compViewDef([elementDef(NodeFlags.None, 4, 'span')].concat(nodes))))
|
||||
compViewDef([elementDef(NodeFlags.None, null, 4, 'span')].concat(nodes))))
|
||||
.toThrowError('No provider for Dep!');
|
||||
});
|
||||
|
||||
it('should inject from a parent elment in a parent view', () => {
|
||||
createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
providerDef(
|
||||
NodeFlags.None, Dep, [], null, null,
|
||||
NodeFlags.None, null, Dep, [], null, null, null,
|
||||
() => compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.None, SomeService, [Dep])
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, null, SomeService, [Dep])
|
||||
])),
|
||||
]));
|
||||
|
||||
@ -124,8 +128,8 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
describe('builtin tokens', () => {
|
||||
it('should inject ViewContainerRef', () => {
|
||||
createAndGetRootNodes(compViewDef([
|
||||
anchorDef(NodeFlags.HasEmbeddedViews, 1),
|
||||
providerDef(NodeFlags.None, SomeService, [ViewContainerRef])
|
||||
anchorDef(NodeFlags.HasEmbeddedViews, null, 1),
|
||||
providerDef(NodeFlags.None, null, SomeService, [ViewContainerRef])
|
||||
]));
|
||||
|
||||
expect(instance.dep.createEmbeddedView).toBeTruthy();
|
||||
@ -133,8 +137,9 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
it('should inject TemplateRef', () => {
|
||||
createAndGetRootNodes(compViewDef([
|
||||
anchorDef(NodeFlags.None, 1, embeddedViewDef([anchorDef(NodeFlags.None, 0)])),
|
||||
providerDef(NodeFlags.None, SomeService, [TemplateRef])
|
||||
anchorDef(
|
||||
NodeFlags.None, null, 1, embeddedViewDef([anchorDef(NodeFlags.None, null, 0)])),
|
||||
providerDef(NodeFlags.None, null, SomeService, [TemplateRef])
|
||||
]));
|
||||
|
||||
expect(instance.dep.createEmbeddedView).toBeTruthy();
|
||||
@ -142,8 +147,8 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
it('should inject ElementRef', () => {
|
||||
createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.None, SomeService, [ElementRef])
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, null, SomeService, [ElementRef])
|
||||
]));
|
||||
|
||||
expect(getDOM().nodeName(instance.dep.nativeElement).toLowerCase()).toBe('span');
|
||||
@ -152,16 +157,16 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
if (config.directDom) {
|
||||
it('should not inject Renderer when using directDom', () => {
|
||||
expect(() => createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.None, SomeService, [Renderer])
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, null, SomeService, [Renderer])
|
||||
])))
|
||||
.toThrowError('No provider for Renderer!');
|
||||
});
|
||||
} else {
|
||||
it('should inject Renderer when not using directDom', () => {
|
||||
createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.None, SomeService, [Renderer])
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, null, SomeService, [Renderer])
|
||||
]));
|
||||
|
||||
expect(instance.dep.createElement).toBeTruthy();
|
||||
@ -193,8 +198,8 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.None, SomeService, [], {a: [0, 'a'], b: [1, 'b']})
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, null, SomeService, [], {a: [0, 'a'], b: [1, 'b']})
|
||||
],
|
||||
config.update));
|
||||
|
||||
@ -213,8 +218,8 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
let propValue = 'v1';
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.None, SomeService, [], {a: [0, 'a']})
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, null, SomeService, [], {a: [0, 'a']})
|
||||
],
|
||||
(updater, view) => updater.checkInline(view, 1, propValue)));
|
||||
|
||||
@ -248,8 +253,8 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.None, SomeService, [], null, {emitter: 'someEventName'})
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, null, SomeService, [], null, {emitter: 'someEventName'})
|
||||
],
|
||||
null, handleEvent));
|
||||
|
||||
@ -286,10 +291,10 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
NodeFlags.AfterViewChecked | NodeFlags.OnDestroy;
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, 3, 'span'),
|
||||
providerDef(allFlags, SomeService, [], {a: [0, 'a']}),
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(allFlags, SomeService, [], {a: [0, 'a']})
|
||||
elementDef(NodeFlags.None, null, 3, 'span'),
|
||||
providerDef(allFlags, null, SomeService, [], {a: [0, 'a']}),
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(allFlags, null, SomeService, [], {a: [0, 'a']})
|
||||
],
|
||||
(updater) => {
|
||||
updater.checkInline(view, 1, 'someValue');
|
||||
@ -345,8 +350,8 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.OnChanges, SomeService, [], {a: [0, 'nonMinifiedA']})
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.OnChanges, null, SomeService, [], {a: [0, 'nonMinifiedA']})
|
||||
],
|
||||
(updater) => updater.checkInline(view, 1, currValue)));
|
||||
|
||||
|
@ -45,8 +45,8 @@ export function main() {
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, 2, 'span'), pureArrayDef(2),
|
||||
providerDef(NodeFlags.None, Service, [], {data: [0, 'data']})
|
||||
elementDef(NodeFlags.None, null, 2, 'span'), pureArrayDef(2),
|
||||
providerDef(NodeFlags.None, null, Service, [], {data: [0, 'data']})
|
||||
],
|
||||
(updater, view) => {
|
||||
callUpdater(
|
||||
@ -79,8 +79,8 @@ export function main() {
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, 2, 'span'), pureObjectDef(['a', 'b']),
|
||||
providerDef(NodeFlags.None, Service, [], {data: [0, 'data']})
|
||||
elementDef(NodeFlags.None, null, 2, 'span'), pureObjectDef(['a', 'b']),
|
||||
providerDef(NodeFlags.None, null, Service, [], {data: [0, 'data']})
|
||||
],
|
||||
(updater, view) => {
|
||||
callUpdater(
|
||||
@ -117,9 +117,9 @@ export function main() {
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(NodeFlags.None, 3, 'span'), providerDef(NodeFlags.None, SomePipe, []),
|
||||
purePipeDef(SomePipe, 2),
|
||||
providerDef(NodeFlags.None, Service, [], {data: [0, 'data']})
|
||||
elementDef(NodeFlags.None, null, 3, 'span'),
|
||||
providerDef(NodeFlags.None, null, SomePipe, []), purePipeDef(SomePipe, 2),
|
||||
providerDef(NodeFlags.None, null, Service, [], {data: [0, 'data']})
|
||||
],
|
||||
(updater, view) => {
|
||||
callUpdater(
|
||||
|
390
modules/@angular/core/test/view/query_spec.ts
Normal file
390
modules/@angular/core/test/view/query_spec.ts
Normal file
@ -0,0 +1,390 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementRef, QueryList, RenderComponentType, RootRenderer, Sanitizer, SecurityContext, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
||||
import {BindingType, DefaultServices, NodeDef, NodeFlags, NodeUpdater, QueryBindingType, QueryValueType, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn, anchorDef, attachEmbeddedView, checkAndUpdateView, checkNoChangesView, createEmbeddedView, createRootView, destroyView, detachEmbeddedView, elementDef, providerDef, rootRenderNodes, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {inject} from '@angular/core/testing';
|
||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||
|
||||
export function main() {
|
||||
describe(`Query Views`, () => {
|
||||
let services: Services;
|
||||
let renderComponentType: RenderComponentType;
|
||||
|
||||
beforeEach(
|
||||
inject([RootRenderer, Sanitizer], (rootRenderer: RootRenderer, sanitizer: Sanitizer) => {
|
||||
services = new DefaultServices(rootRenderer, sanitizer);
|
||||
renderComponentType =
|
||||
new RenderComponentType('1', 'someUrl', 0, ViewEncapsulation.None, [], {});
|
||||
}));
|
||||
|
||||
function compViewDef(
|
||||
nodes: NodeDef[], update?: ViewUpdateFn, handleEvent?: ViewHandleEventFn): ViewDefinition {
|
||||
return viewDef(ViewFlags.None, nodes, update, handleEvent, renderComponentType);
|
||||
}
|
||||
|
||||
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinition {
|
||||
return viewDef(ViewFlags.None, nodes, update);
|
||||
}
|
||||
|
||||
function createAndGetRootNodes(
|
||||
viewDef: ViewDefinition, context: any = null): {rootNodes: any[], view: ViewData} {
|
||||
const view = createRootView(services, viewDef, context);
|
||||
const rootNodes = rootRenderNodes(view);
|
||||
return {rootNodes, view};
|
||||
}
|
||||
|
||||
class AService {}
|
||||
|
||||
class QueryService {
|
||||
a: QueryList<AService>;
|
||||
}
|
||||
|
||||
function contentQueryProvider() {
|
||||
return providerDef(
|
||||
NodeFlags.None, null, QueryService, [], null, null,
|
||||
{'a': ['query1', QueryBindingType.All]});
|
||||
}
|
||||
|
||||
function aServiceProvider() {
|
||||
return providerDef(NodeFlags.None, [['query1', QueryValueType.Provider]], AService, []);
|
||||
}
|
||||
|
||||
function viewQueryProvider(compView: ViewDefinition) {
|
||||
return providerDef(
|
||||
NodeFlags.None, null, QueryService, [], null, null, null, () => compView,
|
||||
{'a': ['query1', QueryBindingType.All]});
|
||||
}
|
||||
|
||||
describe('content queries', () => {
|
||||
|
||||
it('should query providers on the same element and child elements', () => {
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 4, 'div'),
|
||||
contentQueryProvider(),
|
||||
aServiceProvider(),
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
aServiceProvider(),
|
||||
]));
|
||||
|
||||
const qs: QueryService = view.nodes[1].provider.instance;
|
||||
expect(qs.a).toBeUndefined();
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
const as = qs.a.toArray();
|
||||
expect(as.length).toBe(2);
|
||||
expect(as[0]).toBe(view.nodes[2].provider.instance);
|
||||
expect(as[1]).toBe(view.nodes[4].provider.instance);
|
||||
});
|
||||
|
||||
it('should not query providers on sibling or parent elements', () => {
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 5, 'div'),
|
||||
aServiceProvider(),
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
contentQueryProvider(),
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
aServiceProvider(),
|
||||
]));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
const qs: QueryService = view.nodes[3].provider.instance;
|
||||
expect(qs.a.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('view queries', () => {
|
||||
it('should query providers in the view', () => {
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
viewQueryProvider(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
aServiceProvider(),
|
||||
])),
|
||||
]));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
const comp: QueryService = view.nodes[1].provider.instance;
|
||||
const compView = view.nodes[1].provider.componentView;
|
||||
expect(comp.a.length).toBe(1);
|
||||
expect(comp.a.first).toBe(compView.nodes[1].provider.instance);
|
||||
});
|
||||
|
||||
it('should not query providers on the host element', () => {
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 2, 'div'),
|
||||
viewQueryProvider(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
])),
|
||||
aServiceProvider(),
|
||||
]));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
const comp: QueryService = view.nodes[1].provider.instance;
|
||||
expect(comp.a.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('embedded views', () => {
|
||||
it('should query providers in embedded views', () => {
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 3, 'div'),
|
||||
contentQueryProvider(),
|
||||
anchorDef(
|
||||
NodeFlags.HasEmbeddedViews, null, 1, viewDef(
|
||||
ViewFlags.None,
|
||||
[
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
aServiceProvider(),
|
||||
])),
|
||||
contentQueryProvider(),
|
||||
]));
|
||||
|
||||
const childView = createEmbeddedView(view, view.def.nodes[2]);
|
||||
attachEmbeddedView(view.nodes[2], 0, childView);
|
||||
checkAndUpdateView(view);
|
||||
|
||||
// queries on parent elements of anchors
|
||||
const qs1: QueryService = view.nodes[1].provider.instance;
|
||||
expect(qs1.a.length).toBe(1);
|
||||
expect(qs1.a.first instanceof AService).toBe(true);
|
||||
|
||||
// queries on the anchor
|
||||
const qs2: QueryService = view.nodes[3].provider.instance;
|
||||
expect(qs2.a.length).toBe(1);
|
||||
expect(qs2.a.first instanceof AService).toBe(true);
|
||||
});
|
||||
|
||||
it('should query providers in embedded views only at the template declaration', () => {
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 2, 'div'),
|
||||
contentQueryProvider(),
|
||||
anchorDef(
|
||||
NodeFlags.HasEmbeddedViews, null, 0, viewDef(
|
||||
ViewFlags.None,
|
||||
[
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
aServiceProvider(),
|
||||
])),
|
||||
elementDef(NodeFlags.None, null, 2, 'div'),
|
||||
contentQueryProvider(),
|
||||
anchorDef(NodeFlags.HasEmbeddedViews, null, 0),
|
||||
]));
|
||||
|
||||
const childView = createEmbeddedView(view, view.def.nodes[2]);
|
||||
// attach at a different place than the one where the template was defined
|
||||
attachEmbeddedView(view.nodes[5], 0, childView);
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
// query on the declaration place
|
||||
const qs1: QueryService = view.nodes[1].provider.instance;
|
||||
expect(qs1.a.length).toBe(1);
|
||||
expect(qs1.a.first instanceof AService).toBe(true);
|
||||
|
||||
// query on the attach place
|
||||
const qs2: QueryService = view.nodes[4].provider.instance;
|
||||
expect(qs2.a.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should checkNoChanges', () => {
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 3, 'div'),
|
||||
contentQueryProvider(),
|
||||
anchorDef(
|
||||
NodeFlags.HasEmbeddedViews, null, 1, viewDef(
|
||||
ViewFlags.None,
|
||||
[
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
aServiceProvider(),
|
||||
])),
|
||||
]));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
checkNoChangesView(view);
|
||||
|
||||
const childView = createEmbeddedView(view, view.def.nodes[2]);
|
||||
attachEmbeddedView(view.nodes[2], 0, childView);
|
||||
|
||||
expect(() => checkNoChangesView(view))
|
||||
.toThrowError(
|
||||
`Expression has changed after it was checked. Previous value: ''. Current value: '[object Object]'.`);
|
||||
});
|
||||
|
||||
it('should update content queries if embedded views are added or removed', () => {
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 2, 'div'),
|
||||
contentQueryProvider(),
|
||||
anchorDef(
|
||||
NodeFlags.HasEmbeddedViews, null, 0, viewDef(
|
||||
ViewFlags.None,
|
||||
[
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
aServiceProvider(),
|
||||
])),
|
||||
]));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
const qs: QueryService = view.nodes[1].provider.instance;
|
||||
expect(qs.a.length).toBe(0);
|
||||
|
||||
const childView = createEmbeddedView(view, view.def.nodes[2]);
|
||||
attachEmbeddedView(view.nodes[2], 0, childView);
|
||||
checkAndUpdateView(view);
|
||||
|
||||
expect(qs.a.length).toBe(1);
|
||||
|
||||
detachEmbeddedView(view.nodes[2], 0);
|
||||
checkAndUpdateView(view);
|
||||
|
||||
expect(qs.a.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should update view queries if embedded views are added or removed', () => {
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
viewQueryProvider(compViewDef([
|
||||
anchorDef(
|
||||
NodeFlags.HasEmbeddedViews, null, 0,
|
||||
viewDef(
|
||||
ViewFlags.None,
|
||||
[
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
aServiceProvider(),
|
||||
])),
|
||||
])),
|
||||
]));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
const comp: QueryService = view.nodes[1].provider.instance;
|
||||
expect(comp.a.length).toBe(0);
|
||||
|
||||
const compView = view.nodes[1].provider.componentView;
|
||||
const childView = createEmbeddedView(compView, compView.def.nodes[0]);
|
||||
attachEmbeddedView(compView.nodes[0], 0, childView);
|
||||
checkAndUpdateView(view);
|
||||
|
||||
expect(comp.a.length).toBe(1);
|
||||
|
||||
detachEmbeddedView(compView.nodes[0], 0);
|
||||
checkAndUpdateView(view);
|
||||
|
||||
expect(comp.a.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('QueryBindingType', () => {
|
||||
it('should query all matches', () => {
|
||||
class QueryService {
|
||||
a: QueryList<AService>;
|
||||
}
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 3, 'div'),
|
||||
providerDef(
|
||||
NodeFlags.None, null, QueryService, [], null, null,
|
||||
{'a': ['query1', QueryBindingType.All]}),
|
||||
aServiceProvider(),
|
||||
aServiceProvider(),
|
||||
]));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
const qs: QueryService = view.nodes[1].provider.instance;
|
||||
expect(qs.a instanceof QueryList).toBeTruthy();
|
||||
expect(qs.a.toArray()).toEqual([
|
||||
view.nodes[2].provider.instance,
|
||||
view.nodes[3].provider.instance,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should query the first match', () => {
|
||||
class QueryService {
|
||||
a: AService;
|
||||
}
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, null, 3, 'div'),
|
||||
providerDef(
|
||||
NodeFlags.None, null, QueryService, [], null, null,
|
||||
{'a': ['query1', QueryBindingType.First]}),
|
||||
aServiceProvider(),
|
||||
aServiceProvider(),
|
||||
]));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
const qs: QueryService = view.nodes[1].provider.instance;
|
||||
expect(qs.a).toBe(view.nodes[2].provider.instance);
|
||||
});
|
||||
});
|
||||
|
||||
describe('query builtins', () => {
|
||||
it('should query ElementRef', () => {
|
||||
class QueryService {
|
||||
a: ElementRef;
|
||||
}
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, [['query1', QueryValueType.ElementRef]], 1, 'div'),
|
||||
providerDef(
|
||||
NodeFlags.None, null, QueryService, [], null, null,
|
||||
{'a': ['query1', QueryBindingType.First]}),
|
||||
]));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
const qs: QueryService = view.nodes[1].provider.instance;
|
||||
expect(qs.a.nativeElement).toBe(view.nodes[0].elementOrText.node);
|
||||
});
|
||||
|
||||
it('should query TemplateRef', () => {
|
||||
class QueryService {
|
||||
a: TemplateRef<any>;
|
||||
}
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
anchorDef(
|
||||
NodeFlags.None, [['query1', QueryValueType.TemplateRef]], 1,
|
||||
viewDef(ViewFlags.None, [anchorDef(NodeFlags.None, null, 0)])),
|
||||
providerDef(
|
||||
NodeFlags.None, null, QueryService, [], null, null,
|
||||
{'a': ['query1', QueryBindingType.First]}),
|
||||
]));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
const qs: QueryService = view.nodes[1].provider.instance;
|
||||
expect(qs.a.createEmbeddedView).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should query ViewContainerRef', () => {
|
||||
class QueryService {
|
||||
a: ViewContainerRef;
|
||||
}
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
anchorDef(NodeFlags.None, [['query1', QueryValueType.ViewContainerRef]], 1),
|
||||
providerDef(
|
||||
NodeFlags.None, null, QueryService, [], null, null,
|
||||
{'a': ['query1', QueryBindingType.First]}),
|
||||
]));
|
||||
|
||||
checkAndUpdateView(view);
|
||||
|
||||
const qs: QueryService = view.nodes[1].provider.instance;
|
||||
expect(qs.a.createEmbeddedView).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
@ -60,7 +60,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
|
||||
|
||||
it('should create text nodes with parents', () => {
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||
elementDef(NodeFlags.None, 1, 'div'),
|
||||
elementDef(NodeFlags.None, null, 1, 'div'),
|
||||
textDef(['a']),
|
||||
])).rootNodes;
|
||||
expect(rootNodes.length).toBe(1);
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NodeFlags, NodeUpdater, ViewData, ViewDefinition, ViewFlags, anchorDef, checkAndUpdateView, checkNoChangesView, elementDef, providerDef, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {NodeFlags, NodeUpdater, QueryValueType, ViewData, ViewDefinition, ViewFlags, anchorDef, checkAndUpdateView, checkNoChangesView, elementDef, providerDef, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
|
||||
export function main() {
|
||||
describe('viewDef', () => {
|
||||
@ -26,9 +26,9 @@ export function main() {
|
||||
|
||||
it('should reverse child order for one level, one root', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, 2, 'span'), // level 0, index 0
|
||||
textDef(['a']), // level 1, index 1
|
||||
textDef(['a']), // level 1, index 2
|
||||
elementDef(NodeFlags.None, null, 2, 'span'), // level 0, index 0
|
||||
textDef(['a']), // level 1, index 1
|
||||
textDef(['a']), // level 1, index 2
|
||||
]);
|
||||
|
||||
expect(reverseChildOrder(vd)).toEqual([0, 2, 1]);
|
||||
@ -36,11 +36,11 @@ export function main() {
|
||||
|
||||
it('should reverse child order for 1 level, 2 roots', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, 2, 'span'), // level 0, index 0
|
||||
textDef(['a']), // level 1, index 1
|
||||
textDef(['a']), // level 1, index 2
|
||||
elementDef(NodeFlags.None, 1, 'span'), // level 0, index 3
|
||||
textDef(['a']), // level 1, index 4
|
||||
elementDef(NodeFlags.None, null, 2, 'span'), // level 0, index 0
|
||||
textDef(['a']), // level 1, index 1
|
||||
textDef(['a']), // level 1, index 2
|
||||
elementDef(NodeFlags.None, null, 1, 'span'), // level 0, index 3
|
||||
textDef(['a']), // level 1, index 4
|
||||
]);
|
||||
|
||||
expect(reverseChildOrder(vd)).toEqual([3, 4, 0, 2, 1]);
|
||||
@ -48,11 +48,11 @@ export function main() {
|
||||
|
||||
it('should reverse child order for 2 levels', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, 4, 'span'), // level 0, index 0
|
||||
elementDef(NodeFlags.None, 1, 'span'), // level 1, index 1
|
||||
textDef(['a']), // level 2, index 2
|
||||
elementDef(NodeFlags.None, 1, 'span'), // level 1, index 3
|
||||
textDef(['a']), // level 2, index 4
|
||||
elementDef(NodeFlags.None, null, 4, 'span'), // level 0, index 0
|
||||
elementDef(NodeFlags.None, null, 1, 'span'), // level 1, index 1
|
||||
textDef(['a']), // level 2, index 2
|
||||
elementDef(NodeFlags.None, null, 1, 'span'), // level 1, index 3
|
||||
textDef(['a']), // level 2, index 4
|
||||
]);
|
||||
|
||||
expect(reverseChildOrder(vd)).toEqual([0, 3, 4, 1, 2]);
|
||||
@ -60,14 +60,14 @@ export function main() {
|
||||
|
||||
it('should reverse child order for mixed levels', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
textDef(['a']), // level 0, index 0
|
||||
elementDef(NodeFlags.None, 5, 'span'), // level 0, index 1
|
||||
textDef(['a']), // level 1, index 2
|
||||
elementDef(NodeFlags.None, 1, 'span'), // level 1, index 3
|
||||
textDef(['a']), // level 2, index 4
|
||||
elementDef(NodeFlags.None, 1, 'span'), // level 1, index 5
|
||||
textDef(['a']), // level 2, index 6
|
||||
textDef(['a']), // level 0, index 7
|
||||
textDef(['a']), // level 0, index 0
|
||||
elementDef(NodeFlags.None, null, 5, 'span'), // level 0, index 1
|
||||
textDef(['a']), // level 1, index 2
|
||||
elementDef(NodeFlags.None, null, 1, 'span'), // level 1, index 3
|
||||
textDef(['a']), // level 2, index 4
|
||||
elementDef(NodeFlags.None, null, 1, 'span'), // level 1, index 5
|
||||
textDef(['a']), // level 2, index 6
|
||||
textDef(['a']), // level 0, index 7
|
||||
]);
|
||||
|
||||
expect(reverseChildOrder(vd)).toEqual([7, 1, 5, 6, 3, 4, 2, 0]);
|
||||
@ -81,7 +81,7 @@ export function main() {
|
||||
|
||||
it('should calculate parents for one level', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, 2, 'span'),
|
||||
elementDef(NodeFlags.None, null, 2, 'span'),
|
||||
textDef(['a']),
|
||||
textDef(['a']),
|
||||
]);
|
||||
@ -91,9 +91,9 @@ export function main() {
|
||||
|
||||
it('should calculate parents for one level, multiple roots', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
textDef(['a']),
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
textDef(['a']),
|
||||
textDef(['a']),
|
||||
]);
|
||||
@ -103,10 +103,10 @@ export function main() {
|
||||
|
||||
it('should calculate parents for multiple levels', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, 2, 'span'),
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
elementDef(NodeFlags.None, null, 2, 'span'),
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
textDef(['a']),
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
textDef(['a']),
|
||||
textDef(['a']),
|
||||
]);
|
||||
@ -123,20 +123,31 @@ export function main() {
|
||||
|
||||
it('should calculate childFlags for one level', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.AfterContentChecked, AService, [])
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.AfterContentChecked, null, AService, [])
|
||||
]);
|
||||
|
||||
expect(childFlags(vd)).toEqual([NodeFlags.AfterContentChecked, NodeFlags.None]);
|
||||
});
|
||||
|
||||
it('should calculate childFlags for two levels', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, null, 2, 'span'), elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.AfterContentChecked, null, AService, [])
|
||||
]);
|
||||
|
||||
expect(childFlags(vd)).toEqual([
|
||||
NodeFlags.AfterContentChecked, NodeFlags.AfterContentChecked, NodeFlags.None
|
||||
]);
|
||||
});
|
||||
|
||||
it('should calculate childFlags for one level, multiple roots', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.AfterContentChecked, AService, []),
|
||||
elementDef(NodeFlags.None, 2, 'span'),
|
||||
providerDef(NodeFlags.AfterContentInit, AService, []),
|
||||
providerDef(NodeFlags.AfterViewChecked, AService, []),
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.AfterContentChecked, null, AService, []),
|
||||
elementDef(NodeFlags.None, null, 2, 'span'),
|
||||
providerDef(NodeFlags.AfterContentInit, null, AService, []),
|
||||
providerDef(NodeFlags.AfterViewChecked, null, AService, []),
|
||||
]);
|
||||
|
||||
expect(childFlags(vd)).toEqual([
|
||||
@ -147,12 +158,12 @@ export function main() {
|
||||
|
||||
it('should calculate childFlags for multiple levels', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, 2, 'span'),
|
||||
elementDef(NodeFlags.None, 1, 'span'),
|
||||
providerDef(NodeFlags.AfterContentChecked, AService, []),
|
||||
elementDef(NodeFlags.None, 2, 'span'),
|
||||
providerDef(NodeFlags.AfterContentInit, AService, []),
|
||||
providerDef(NodeFlags.AfterViewInit, AService, []),
|
||||
elementDef(NodeFlags.None, null, 2, 'span'),
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.AfterContentChecked, null, AService, []),
|
||||
elementDef(NodeFlags.None, null, 2, 'span'),
|
||||
providerDef(NodeFlags.AfterContentInit, null, AService, []),
|
||||
providerDef(NodeFlags.AfterViewInit, null, AService, []),
|
||||
]);
|
||||
|
||||
expect(childFlags(vd)).toEqual([
|
||||
@ -161,6 +172,71 @@ export function main() {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('childMatchedQueries', () => {
|
||||
function childMatchedQueries(viewDef: ViewDefinition): string[][] {
|
||||
return viewDef.nodes.map(node => Object.keys(node.childMatchedQueries).sort());
|
||||
}
|
||||
|
||||
it('should calculate childMatchedQueries for one level', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, [['q1', QueryValueType.Provider]], AService, [])
|
||||
]);
|
||||
|
||||
expect(childMatchedQueries(vd)).toEqual([['q1'], []]);
|
||||
});
|
||||
|
||||
it('should calculate childMatchedQueries for two levels', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, null, 2, 'span'), elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, [['q1', QueryValueType.Provider]], AService, [])
|
||||
]);
|
||||
|
||||
expect(childMatchedQueries(vd)).toEqual([['q1'], ['q1'], []]);
|
||||
});
|
||||
|
||||
it('should calculate childMatchedQueries for one level, multiple roots', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, [['q1', QueryValueType.Provider]], AService, []),
|
||||
elementDef(NodeFlags.None, null, 2, 'span'),
|
||||
providerDef(NodeFlags.None, [['q2', QueryValueType.Provider]], AService, []),
|
||||
providerDef(NodeFlags.None, [['q3', QueryValueType.Provider]], AService, []),
|
||||
]);
|
||||
|
||||
expect(childMatchedQueries(vd)).toEqual([['q1'], [], ['q2', 'q3'], [], []]);
|
||||
});
|
||||
|
||||
it('should calculate childMatchedQueries for multiple levels', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, null, 2, 'span'),
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
providerDef(NodeFlags.None, [['q1', QueryValueType.Provider]], AService, []),
|
||||
elementDef(NodeFlags.None, null, 2, 'span'),
|
||||
providerDef(NodeFlags.None, [['q2', QueryValueType.Provider]], AService, []),
|
||||
providerDef(NodeFlags.None, [['q3', QueryValueType.Provider]], AService, []),
|
||||
]);
|
||||
|
||||
expect(childMatchedQueries(vd)).toEqual([['q1'], ['q1'], [], ['q2', 'q3'], [], []]);
|
||||
});
|
||||
|
||||
it('should included embedded views into childMatchedQueries', () => {
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(NodeFlags.None, null, 1, 'span'),
|
||||
anchorDef(
|
||||
NodeFlags.None, null, 0,
|
||||
viewDef(
|
||||
ViewFlags.None,
|
||||
[
|
||||
elementDef(NodeFlags.None, [['q1', QueryValueType.Provider]], 1, 'span'),
|
||||
]))
|
||||
]);
|
||||
|
||||
// Note: the template will become a sibling to the anchor once stamped out,
|
||||
expect(childMatchedQueries(vd)).toEqual([['q1'], []]);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user