@ -8,13 +8,12 @@
|
||||
|
||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {getDebugNode} from '@angular/core';
|
||||
import {NodeFlags, anchorDef, asElementData, elementDef} from '@angular/core/src/view/index';
|
||||
import {anchorDef, asElementData, elementDef, NodeFlags} from '@angular/core/src/view/index';
|
||||
|
||||
import {compViewDef, createAndGetRootNodes} from './helper';
|
||||
|
||||
{
|
||||
describe(`View Anchor`, () => {
|
||||
|
||||
describe('create', () => {
|
||||
it('should create anchor nodes without parents', () => {
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||
@ -43,7 +42,7 @@ import {compViewDef, createAndGetRootNodes} from './helper';
|
||||
const someContext = {};
|
||||
const {view, rootNodes} = createAndGetRootNodes(
|
||||
compViewDef([anchorDef(NodeFlags.None, null, null, 0)]), someContext);
|
||||
expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asElementData(view, 0).renderElement);
|
||||
expect(getDebugNode(rootNodes[0])!.nativeNode).toBe(asElementData(view, 0).renderElement);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {SecurityContext} from '@angular/core';
|
||||
import {ArgumentType, BindingFlags, NodeCheckFn, NodeFlags, Services, ViewData, ViewFlags, ViewState, asElementData, directiveDef, elementDef, rootRenderNodes} from '@angular/core/src/view/index';
|
||||
import {ArgumentType, asElementData, BindingFlags, directiveDef, elementDef, NodeCheckFn, NodeFlags, rootRenderNodes, Services, ViewData, ViewFlags, ViewState} from '@angular/core/src/view/index';
|
||||
|
||||
import {callMostRecentEventListenerHandler, compViewDef, createAndGetRootNodes, createRootView, isBrowser, recordNodeToRemove} from './helper';
|
||||
|
||||
@ -23,9 +23,11 @@ const addEventListener = 'addEventListener';
|
||||
{
|
||||
describe(`Component Views`, () => {
|
||||
it('should create and attach component views', () => {
|
||||
let instance: AComp = undefined !;
|
||||
let instance: AComp = undefined!;
|
||||
class AComp {
|
||||
constructor() { instance = this; }
|
||||
constructor() {
|
||||
instance = this;
|
||||
}
|
||||
}
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
@ -108,15 +110,18 @@ const addEventListener = 'addEventListener';
|
||||
check(view, 0, ArgumentType.Inline, value);
|
||||
});
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(
|
||||
compViewDef([
|
||||
elementDef(0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => compViewDef(
|
||||
[
|
||||
elementDef(0, NodeFlags.None, null, null, 0, 'span', null, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]),
|
||||
], null, update
|
||||
)),
|
||||
directiveDef(1, NodeFlags.Component, null, 0, AComp, []),
|
||||
]));
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(
|
||||
0, NodeFlags.None, null, null, 1, 'div', null, null, null, null,
|
||||
() => compViewDef(
|
||||
[
|
||||
elementDef(
|
||||
0, NodeFlags.None, null, null, 0, 'span', null,
|
||||
[[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]),
|
||||
],
|
||||
null, update)),
|
||||
directiveDef(1, NodeFlags.Component, null, 0, AComp, []),
|
||||
]));
|
||||
const compView = asElementData(view, 0).componentView;
|
||||
|
||||
value = 'v1';
|
||||
@ -218,13 +223,15 @@ const addEventListener = 'addEventListener';
|
||||
[
|
||||
elementDef(
|
||||
0, NodeFlags.None, null, null, 0, 'span', null, null,
|
||||
[[null !, 'click']]),
|
||||
[[null!, 'click']]),
|
||||
],
|
||||
update, null, ViewFlags.OnPush);
|
||||
}),
|
||||
directiveDef(1, NodeFlags.Component, null, 0, AComp, [], {a: [0, 'a']}),
|
||||
],
|
||||
(check, view) => { check(view, 1, ArgumentType.Inline, compInputValue); }));
|
||||
(check, view) => {
|
||||
check(view, 1, ArgumentType.Inline, compInputValue);
|
||||
}));
|
||||
|
||||
Services.checkAndUpdateView(view);
|
||||
|
||||
@ -272,10 +279,21 @@ const addEventListener = 'addEventListener';
|
||||
0, NodeFlags.None, null, null, 0, 'span', null,
|
||||
[[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]])],
|
||||
null, update)),
|
||||
directiveDef(1, NodeFlags.Component, null, 0, AComp, [], null, null, ),
|
||||
directiveDef(
|
||||
1,
|
||||
NodeFlags.Component,
|
||||
null,
|
||||
0,
|
||||
AComp,
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
),
|
||||
]));
|
||||
|
||||
update.and.callFake((check: NodeCheckFn, view: ViewData) => { throw new Error('Test'); });
|
||||
update.and.callFake((check: NodeCheckFn, view: ViewData) => {
|
||||
throw new Error('Test');
|
||||
});
|
||||
expect(() => Services.checkAndUpdateView(view)).toThrowError('Test');
|
||||
expect(update).toHaveBeenCalled();
|
||||
|
||||
@ -283,7 +301,6 @@ const addEventListener = 'addEventListener';
|
||||
expect(() => Services.checkAndUpdateView(view)).toThrowError('Test');
|
||||
expect(update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('destroy', () => {
|
||||
@ -293,7 +310,9 @@ const addEventListener = 'addEventListener';
|
||||
class AComp {}
|
||||
|
||||
class ChildProvider {
|
||||
ngOnDestroy() { log.push('ngOnDestroy'); }
|
||||
ngOnDestroy() {
|
||||
log.push('ngOnDestroy');
|
||||
}
|
||||
}
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
@ -303,7 +322,16 @@ const addEventListener = 'addEventListener';
|
||||
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
|
||||
directiveDef(1, NodeFlags.OnDestroy, null, 0, ChildProvider, [])
|
||||
])),
|
||||
directiveDef(1, NodeFlags.Component, null, 0, AComp, [], null, null, ),
|
||||
directiveDef(
|
||||
1,
|
||||
NodeFlags.Component,
|
||||
null,
|
||||
0,
|
||||
AComp,
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
),
|
||||
]));
|
||||
|
||||
Services.destroyView(view);
|
||||
@ -321,6 +349,5 @@ const addEventListener = 'addEventListener';
|
||||
.toThrowError('ViewDestroyedError: Attempt to use a destroyed view: detectChanges');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -7,9 +7,9 @@
|
||||
*/
|
||||
|
||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {ErrorHandler, SecurityContext, getDebugNode} from '@angular/core';
|
||||
import {ErrorHandler, getDebugNode, SecurityContext} from '@angular/core';
|
||||
import {getDebugContext} from '@angular/core/src/errors';
|
||||
import {BindingFlags, NodeFlags, Services, ViewData, ViewDefinition, asElementData, elementDef} from '@angular/core/src/view/index';
|
||||
import {asElementData, BindingFlags, elementDef, NodeFlags, Services, ViewData, ViewDefinition} from '@angular/core/src/view/index';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
|
||||
import {ARG_TYPE_VALUES, callMostRecentEventListenerHandler, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes, isBrowser, recordNodeToRemove} from './helper';
|
||||
@ -25,7 +25,6 @@ const removeEventListener = 'removeEventListener';
|
||||
|
||||
{
|
||||
describe(`View Elements`, () => {
|
||||
|
||||
describe('create', () => {
|
||||
it('should create elements without parents', () => {
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([
|
||||
@ -65,14 +64,13 @@ const removeEventListener = 'removeEventListener';
|
||||
const someContext = {};
|
||||
const {view, rootNodes} = createAndGetRootNodes(
|
||||
compViewDef([elementDef(0, NodeFlags.None, null, null, 0, 'div')]), someContext);
|
||||
expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asElementData(view, 0).renderElement);
|
||||
expect(getDebugNode(rootNodes[0])!.nativeNode).toBe(asElementData(view, 0).renderElement);
|
||||
});
|
||||
});
|
||||
|
||||
describe('change properties', () => {
|
||||
ARG_TYPE_VALUES.forEach((inlineDynamic) => {
|
||||
it(`should update via strategy ${inlineDynamic}`, () => {
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(
|
||||
@ -189,7 +187,7 @@ const removeEventListener = 'removeEventListener';
|
||||
const removeListenerSpy =
|
||||
spyOn(HTMLElement.prototype, removeEventListener).and.callThrough();
|
||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
|
||||
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']],
|
||||
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null!, 'click']],
|
||||
handleEventSpy)]));
|
||||
|
||||
rootNodes[0].click();
|
||||
@ -253,10 +251,10 @@ const removeEventListener = 'removeEventListener';
|
||||
|
||||
it('should preventDefault only if the handler returns false', () => {
|
||||
let eventHandlerResult: any;
|
||||
let preventDefaultSpy: jasmine.Spy = undefined !;
|
||||
let preventDefaultSpy: jasmine.Spy = undefined!;
|
||||
|
||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
|
||||
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']],
|
||||
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null!, 'click']],
|
||||
(view, eventName, event) => {
|
||||
preventDefaultSpy = spyOn(event, 'preventDefault').and.callThrough();
|
||||
return eventHandlerResult;
|
||||
@ -283,8 +281,9 @@ const removeEventListener = 'removeEventListener';
|
||||
const handleErrorSpy = spyOn(TestBed.inject(ErrorHandler), 'handleError');
|
||||
const addListenerSpy = spyOn(HTMLElement.prototype, addEventListener).and.callThrough();
|
||||
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
|
||||
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']],
|
||||
() => { throw new Error('Test'); })]));
|
||||
0, NodeFlags.None, null, null, 0, 'button', null, null, [[null!, 'click']], () => {
|
||||
throw new Error('Test');
|
||||
})]));
|
||||
|
||||
callMostRecentEventListenerHandler(addListenerSpy, 'SomeEvent');
|
||||
const err = handleErrorSpy.calls.mostRecent().args[0];
|
||||
|
@ -8,13 +8,12 @@
|
||||
|
||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {SecurityContext} from '@angular/core';
|
||||
import {ArgumentType, BindingFlags, NodeCheckFn, NodeFlags, Services, ViewData, anchorDef, asElementData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, moveEmbeddedView, rootRenderNodes} from '@angular/core/src/view/index';
|
||||
import {anchorDef, ArgumentType, asElementData, attachEmbeddedView, BindingFlags, detachEmbeddedView, directiveDef, elementDef, moveEmbeddedView, NodeCheckFn, NodeFlags, rootRenderNodes, Services, ViewData} from '@angular/core/src/view/index';
|
||||
|
||||
import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedView} from './helper';
|
||||
|
||||
{
|
||||
describe(`Embedded Views`, () => {
|
||||
|
||||
it('should create embedded views with the right context', () => {
|
||||
const parentContext = {};
|
||||
const childContext = {};
|
||||
@ -39,9 +38,9 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([
|
||||
elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
|
||||
])),
|
||||
anchorDef(NodeFlags.None, null, null, 0, null, compViewDefFactory([elementDef(
|
||||
0, NodeFlags.None, null, null, 0, 'span',
|
||||
[['name', 'child1']])]))
|
||||
anchorDef(NodeFlags.None, null, null, 0, null, compViewDefFactory([
|
||||
elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child1']])
|
||||
]))
|
||||
]));
|
||||
const viewContainerData = asElementData(parentView, 1);
|
||||
const rf = parentView.root.rendererFactory;
|
||||
@ -58,10 +57,10 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
expect(rootChildren[1].getAttribute('name')).toBe('child0');
|
||||
expect(rootChildren[2].getAttribute('name')).toBe('child1');
|
||||
|
||||
rf.begin !();
|
||||
rf.begin!();
|
||||
detachEmbeddedView(viewContainerData, 1);
|
||||
detachEmbeddedView(viewContainerData, 0);
|
||||
rf.end !();
|
||||
rf.end!();
|
||||
|
||||
expect(rootNodes[0].childNodes.length).toBe(2);
|
||||
});
|
||||
@ -72,9 +71,9 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([
|
||||
elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
|
||||
])),
|
||||
anchorDef(NodeFlags.None, null, null, 0, null, compViewDefFactory([elementDef(
|
||||
0, NodeFlags.None, null, null, 0, 'span',
|
||||
[['name', 'child1']])]))
|
||||
anchorDef(NodeFlags.None, null, null, 0, null, compViewDefFactory([
|
||||
elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child1']])
|
||||
]))
|
||||
]));
|
||||
const viewContainerData = asElementData(parentView, 1);
|
||||
|
||||
@ -86,7 +85,7 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
|
||||
moveEmbeddedView(viewContainerData, 0, 1);
|
||||
|
||||
expect(viewContainerData.viewContainer !._embeddedViews).toEqual([childView1, childView0]);
|
||||
expect(viewContainerData.viewContainer!._embeddedViews).toEqual([childView1, childView0]);
|
||||
// 2 anchors + 2 elements
|
||||
const rootChildren = rootNodes[0].childNodes;
|
||||
expect(rootChildren.length).toBe(4);
|
||||
@ -152,7 +151,9 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
const log: string[] = [];
|
||||
|
||||
class ChildProvider {
|
||||
ngOnDestroy() { log.push('ngOnDestroy'); }
|
||||
ngOnDestroy() {
|
||||
log.push('ngOnDestroy');
|
||||
}
|
||||
}
|
||||
|
||||
const {view: parentView} = createAndGetRootNodes(compViewDef([
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {Injector, NgModuleRef} from '@angular/core';
|
||||
import {ArgumentType, NodeCheckFn, NodeDef, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewUpdateFn, initServicesIfNeeded, rootRenderNodes, viewDef} from '@angular/core/src/view/index';
|
||||
import {ArgumentType, initServicesIfNeeded, NodeCheckFn, NodeDef, rootRenderNodes, Services, ViewData, viewDef, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewUpdateFn} from '@angular/core/src/view/index';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
|
||||
export function isBrowser() {
|
||||
@ -38,11 +38,11 @@ export function createRootView(
|
||||
}
|
||||
|
||||
export function createEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData {
|
||||
return Services.createEmbeddedView(parent, anchorDef, anchorDef.element !.template !, context);
|
||||
return Services.createEmbeddedView(parent, anchorDef, anchorDef.element!.template !, context);
|
||||
}
|
||||
|
||||
export function compViewDef(
|
||||
nodes: NodeDef[], updateDirectives?: null | ViewUpdateFn, updateRenderer?: null | ViewUpdateFn,
|
||||
nodes: NodeDef[], updateDirectives?: null|ViewUpdateFn, updateRenderer?: null|ViewUpdateFn,
|
||||
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
|
||||
const def = viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
|
||||
|
||||
@ -53,8 +53,8 @@ export function compViewDef(
|
||||
|
||||
// This check should be removed when we start reordering nodes at runtime
|
||||
if (node.checkIndex > -1 && node.checkIndex !== node.nodeIndex) {
|
||||
throw new Error(
|
||||
`nodeIndex and checkIndex should be the same, got ${node.nodeIndex} !== ${node.checkIndex}`);
|
||||
throw new Error(`nodeIndex and checkIndex should be the same, got ${node.nodeIndex} !== ${
|
||||
node.checkIndex}`);
|
||||
}
|
||||
});
|
||||
|
||||
@ -62,7 +62,7 @@ export function compViewDef(
|
||||
}
|
||||
|
||||
export function compViewDefFactory(
|
||||
nodes: NodeDef[], updateDirectives?: null | ViewUpdateFn, updateRenderer?: null | ViewUpdateFn,
|
||||
nodes: NodeDef[], updateDirectives?: null|ViewUpdateFn, updateRenderer?: null|ViewUpdateFn,
|
||||
viewFlags: ViewFlags = ViewFlags.None): ViewDefinitionFactory {
|
||||
return () => compViewDef(nodes, updateDirectives, updateRenderer, viewFlags);
|
||||
}
|
||||
@ -76,8 +76,12 @@ export function createAndGetRootNodes(
|
||||
|
||||
let removeNodes: Node[];
|
||||
|
||||
beforeEach(() => { removeNodes = []; });
|
||||
afterEach(() => { removeNodes.forEach((node) => getDOM().remove(node)); });
|
||||
beforeEach(() => {
|
||||
removeNodes = [];
|
||||
});
|
||||
afterEach(() => {
|
||||
removeNodes.forEach((node) => getDOM().remove(node));
|
||||
});
|
||||
|
||||
export function recordNodeToRemove(node: Node) {
|
||||
removeNodes.push(node);
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {TemplateRef, ViewContainerRef} from '@angular/core';
|
||||
import {NodeDef, NodeFlags, ViewData, ViewDefinition, anchorDef, asElementData, asTextData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, ngContentDef, rootRenderNodes, textDef} from '@angular/core/src/view/index';
|
||||
import {anchorDef, asElementData, asTextData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, ngContentDef, NodeDef, NodeFlags, rootRenderNodes, textDef, ViewData, ViewDefinition} from '@angular/core/src/view/index';
|
||||
|
||||
import {compViewDef, compViewDefFactory, createEmbeddedView, createRootView, isBrowser} from './helper';
|
||||
|
||||
@ -74,27 +74,23 @@ import {compViewDef, compViewDefFactory, createEmbeddedView, createRootView, isB
|
||||
}
|
||||
}
|
||||
|
||||
const {view, rootNodes} =
|
||||
createAndGetRootNodes(
|
||||
compViewDef(
|
||||
hostElDef(0,
|
||||
[
|
||||
anchorDef(
|
||||
NodeFlags.EmbeddedViews, null, 0, 1, null,
|
||||
compViewDefFactory([textDef(0, null, ['a'])])),
|
||||
directiveDef(3,
|
||||
NodeFlags.None, null, 0, CreateViewService,
|
||||
[TemplateRef, ViewContainerRef]),
|
||||
],
|
||||
[
|
||||
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
|
||||
ngContentDef(null, 0),
|
||||
])));
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(hostElDef(
|
||||
0,
|
||||
[
|
||||
anchorDef(NodeFlags.EmbeddedViews, null, 0, 1, null, compViewDefFactory([textDef(
|
||||
0, null, ['a'])])),
|
||||
directiveDef(
|
||||
3, NodeFlags.None, null, 0, CreateViewService, [TemplateRef, ViewContainerRef]),
|
||||
],
|
||||
[
|
||||
elementDef(0, NodeFlags.None, null, null, 1, 'div'),
|
||||
ngContentDef(null, 0),
|
||||
])));
|
||||
|
||||
const anchor = asElementData(view, 2);
|
||||
const child = rootNodes[0].firstChild;
|
||||
expect(child.childNodes[0]).toBe(anchor.renderElement);
|
||||
const embeddedView = anchor.viewContainer !._embeddedViews[0];
|
||||
const embeddedView = anchor.viewContainer!._embeddedViews[0];
|
||||
expect(child.childNodes[1]).toBe(asTextData(embeddedView, 0).renderText);
|
||||
});
|
||||
|
||||
@ -118,9 +114,9 @@ import {compViewDef, compViewDefFactory, createEmbeddedView, createRootView, isB
|
||||
expect(child.childNodes.length).toBe(3);
|
||||
expect(child.childNodes[1]).toBe(asTextData(view, 2).renderText);
|
||||
|
||||
rf.begin !();
|
||||
rf.begin!();
|
||||
detachEmbeddedView(asElementData(componentView, 1), 0);
|
||||
rf.end !();
|
||||
rf.end!();
|
||||
child = rootNodes[0].firstChild;
|
||||
expect(child.childNodes.length).toBe(1);
|
||||
});
|
||||
|
@ -7,10 +7,10 @@
|
||||
*/
|
||||
|
||||
import {NgModuleRef, ɵINJECTOR_SCOPE as INJECTOR_SCOPE} from '@angular/core';
|
||||
import {InjectFlags, inject} from '@angular/core/src/di';
|
||||
import {inject, InjectFlags} from '@angular/core/src/di';
|
||||
import {Injector} from '@angular/core/src/di/injector';
|
||||
import {INJECTOR} from '@angular/core/src/di/injector_compatibility';
|
||||
import {ɵɵInjectableDef, ɵɵdefineInjectable} from '@angular/core/src/di/interface/defs';
|
||||
import {ɵɵdefineInjectable, ɵɵInjectableDef} from '@angular/core/src/di/interface/defs';
|
||||
import {NgModuleDefinition, NgModuleProviderDef, NodeFlags} from '@angular/core/src/view';
|
||||
import {moduleDef} from '@angular/core/src/view/ng_module';
|
||||
import {createNgModuleRef} from '@angular/core/src/view/refs';
|
||||
@ -94,25 +94,28 @@ class FromChildWithSkipSelfDep {
|
||||
static ɵprov: ɵɵInjectableDef<FromChildWithSkipSelfDep> = ɵɵdefineInjectable({
|
||||
token: FromChildWithSkipSelfDep,
|
||||
factory: () => new FromChildWithSkipSelfDep(
|
||||
inject(ChildDep, InjectFlags.SkipSelf|InjectFlags.Optional),
|
||||
inject(ChildDep, InjectFlags.Self),
|
||||
inject(Bar, InjectFlags.Self|InjectFlags.Optional), ),
|
||||
inject(ChildDep, InjectFlags.SkipSelf|InjectFlags.Optional),
|
||||
inject(ChildDep, InjectFlags.Self),
|
||||
inject(Bar, InjectFlags.Self|InjectFlags.Optional),
|
||||
),
|
||||
providedIn: MyChildModule,
|
||||
});
|
||||
}
|
||||
|
||||
class UsesInject {
|
||||
constructor() { inject(INJECTOR); }
|
||||
constructor() {
|
||||
inject(INJECTOR);
|
||||
}
|
||||
}
|
||||
|
||||
function makeProviders(classes: any[], modules: any[]): NgModuleDefinition {
|
||||
const providers =
|
||||
classes.map((token, index) => ({
|
||||
index,
|
||||
deps: [],
|
||||
flags: NodeFlags.TypeClassProvider | NodeFlags.LazyProvider, token,
|
||||
value: token,
|
||||
}));
|
||||
const providers = classes.map((token, index) => ({
|
||||
index,
|
||||
deps: [],
|
||||
flags: NodeFlags.TypeClassProvider | NodeFlags.LazyProvider,
|
||||
token,
|
||||
value: token,
|
||||
}));
|
||||
return makeModule(modules, providers);
|
||||
}
|
||||
|
||||
@ -144,14 +147,17 @@ describe('NgModuleRef_ injector', () => {
|
||||
MyChildModule, ref.injector, [], makeProviders([MyChildModule], [MyChildModule]));
|
||||
});
|
||||
|
||||
it('injects a provided value',
|
||||
() => { expect(ref.injector.get(Foo) instanceof Foo).toBeTruthy(); });
|
||||
it('injects a provided value', () => {
|
||||
expect(ref.injector.get(Foo) instanceof Foo).toBeTruthy();
|
||||
});
|
||||
|
||||
it('injects an InjectableDef value',
|
||||
() => { expect(ref.injector.get(Bar) instanceof Bar).toBeTruthy(); });
|
||||
it('injects an InjectableDef value', () => {
|
||||
expect(ref.injector.get(Bar) instanceof Bar).toBeTruthy();
|
||||
});
|
||||
|
||||
it('caches InjectableDef values',
|
||||
() => { expect(ref.injector.get(Bar)).toBe(ref.injector.get(Bar)); });
|
||||
it('caches InjectableDef values', () => {
|
||||
expect(ref.injector.get(Bar)).toBe(ref.injector.get(Bar));
|
||||
});
|
||||
|
||||
it('injects provided deps properly', () => {
|
||||
const instance = ref.injector.get(HasNormalDep);
|
||||
@ -179,27 +185,32 @@ describe('NgModuleRef_ injector', () => {
|
||||
expect(instance.optionalSelfBar).toBeNull();
|
||||
});
|
||||
|
||||
it('does not inject something not scoped to the module',
|
||||
() => { expect(ref.injector.get(Baz, null)).toBeNull(); });
|
||||
it('does not inject something not scoped to the module', () => {
|
||||
expect(ref.injector.get(Baz, null)).toBeNull();
|
||||
});
|
||||
|
||||
it('injects with the current injector always set',
|
||||
() => { expect(() => ref.injector.get(UsesInject)).not.toThrow(); });
|
||||
it('injects with the current injector always set', () => {
|
||||
expect(() => ref.injector.get(UsesInject)).not.toThrow();
|
||||
});
|
||||
|
||||
it('calls ngOnDestroy on services created via factory', () => {
|
||||
class Module {}
|
||||
|
||||
class Service {
|
||||
static destroyed = 0;
|
||||
ngOnDestroy(): void { Service.destroyed++; }
|
||||
ngOnDestroy(): void {
|
||||
Service.destroyed++;
|
||||
}
|
||||
}
|
||||
|
||||
const ref = createNgModuleRef(
|
||||
Module, Injector.NULL, [], makeFactoryProviders(
|
||||
[{
|
||||
token: Service,
|
||||
factory: () => new Service(),
|
||||
}],
|
||||
[Module]));
|
||||
Module, Injector.NULL, [],
|
||||
makeFactoryProviders(
|
||||
[{
|
||||
token: Service,
|
||||
factory: () => new Service(),
|
||||
}],
|
||||
[Module]));
|
||||
|
||||
expect(ref.injector.get(Service)).toBeDefined();
|
||||
expect(Service.destroyed).toBe(0);
|
||||
@ -213,7 +224,9 @@ describe('NgModuleRef_ injector', () => {
|
||||
class Service {
|
||||
static destroyed = 0;
|
||||
|
||||
ngOnDestroy(): void { Service.destroyed++; }
|
||||
ngOnDestroy(): void {
|
||||
Service.destroyed++;
|
||||
}
|
||||
|
||||
static ɵprov: ɵɵInjectableDef<Service> = ɵɵdefineInjectable({
|
||||
token: Service,
|
||||
@ -235,25 +248,28 @@ describe('NgModuleRef_ injector', () => {
|
||||
|
||||
class Service {
|
||||
static destroyed = 0;
|
||||
ngOnDestroy(): void { Service.destroyed++; }
|
||||
ngOnDestroy(): void {
|
||||
Service.destroyed++;
|
||||
}
|
||||
}
|
||||
|
||||
class OtherToken {}
|
||||
|
||||
const instance = new Service();
|
||||
const ref = createNgModuleRef(
|
||||
Module, Injector.NULL, [], makeFactoryProviders(
|
||||
[
|
||||
{
|
||||
token: Service,
|
||||
factory: () => instance,
|
||||
},
|
||||
{
|
||||
token: OtherToken,
|
||||
factory: () => instance,
|
||||
}
|
||||
],
|
||||
[Module]));
|
||||
Module, Injector.NULL, [],
|
||||
makeFactoryProviders(
|
||||
[
|
||||
{
|
||||
token: Service,
|
||||
factory: () => instance,
|
||||
},
|
||||
{
|
||||
token: OtherToken,
|
||||
factory: () => instance,
|
||||
}
|
||||
],
|
||||
[Module]));
|
||||
|
||||
expect(ref.injector.get(Service)).toBe(instance);
|
||||
expect(ref.injector.get(OtherToken)).toBe(instance);
|
||||
@ -267,7 +283,9 @@ describe('NgModuleRef_ injector', () => {
|
||||
return {
|
||||
index: 0,
|
||||
flags: NodeFlags.TypeValueProvider | NodeFlags.LazyProvider,
|
||||
deps: [], token, value
|
||||
deps: [],
|
||||
token,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -6,26 +6,29 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectorRef, DoCheck, ElementRef, ErrorHandler, EventEmitter, Injector, OnChanges, OnDestroy, OnInit, Renderer2, SimpleChange, TemplateRef, ViewContainerRef,} from '@angular/core';
|
||||
import {getDebugContext} from '@angular/core/src/errors';
|
||||
import {ArgumentType, DepFlags, NodeFlags, Services, anchorDef, asElementData, directiveDef, elementDef, providerDef, textDef} from '@angular/core/src/view/index';
|
||||
import {anchorDef, ArgumentType, asElementData, DepFlags, directiveDef, elementDef, NodeFlags, providerDef, Services, textDef} from '@angular/core/src/view/index';
|
||||
import {TestBed, withModule} from '@angular/core/testing';
|
||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {ivyEnabled} from '@angular/private/testing';
|
||||
|
||||
import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetRootNodes, compViewDef, compViewDefFactory} from './helper';
|
||||
import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, compViewDefFactory, createAndGetRootNodes, createRootView} from './helper';
|
||||
|
||||
{
|
||||
describe(`View Providers`, () => {
|
||||
|
||||
describe('create', () => {
|
||||
let instance: SomeService;
|
||||
|
||||
class SomeService {
|
||||
constructor(public dep: any) { instance = this; }
|
||||
constructor(public dep: any) {
|
||||
instance = this;
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => { instance = null !; });
|
||||
beforeEach(() => {
|
||||
instance = null!;
|
||||
});
|
||||
|
||||
it('should create providers eagerly', () => {
|
||||
createAndGetRootNodes(compViewDef([
|
||||
@ -37,9 +40,11 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
});
|
||||
|
||||
it('should create providers lazily', () => {
|
||||
let lazy: LazyService = undefined !;
|
||||
let lazy: LazyService = undefined!;
|
||||
class LazyService {
|
||||
constructor() { lazy = this; }
|
||||
constructor() {
|
||||
lazy = this;
|
||||
}
|
||||
}
|
||||
|
||||
createAndGetRootNodes(compViewDef([
|
||||
@ -66,7 +71,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
});
|
||||
|
||||
it('should create factory providers', () => {
|
||||
function someFactory() { return 'someValue'; }
|
||||
function someFactory() {
|
||||
return 'someValue';
|
||||
}
|
||||
|
||||
createAndGetRootNodes(compViewDef([
|
||||
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
|
||||
@ -91,7 +98,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
|
||||
it('should add a DebugContext to errors in provider factories', () => {
|
||||
class SomeService {
|
||||
constructor() { throw new Error('Test'); }
|
||||
constructor() {
|
||||
throw new Error('Test');
|
||||
}
|
||||
}
|
||||
|
||||
let err: any;
|
||||
@ -148,7 +157,10 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
|
||||
expect(() => createAndGetRootNodes(compViewDef(rootElNodes)))
|
||||
.toThrowError(
|
||||
`${ivyEnabled ? 'R3InjectorError' : 'StaticInjectorError'}(DynamicTestModule)[SomeService -> Dep]: \n` +
|
||||
`${
|
||||
ivyEnabled ?
|
||||
'R3InjectorError' :
|
||||
'StaticInjectorError'}(DynamicTestModule)[SomeService -> Dep]: \n` +
|
||||
' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' +
|
||||
' NullInjectorError: No provider for Dep!');
|
||||
|
||||
@ -162,7 +174,10 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
|
||||
expect(() => createAndGetRootNodes(compViewDef(nonRootElNodes)))
|
||||
.toThrowError(
|
||||
`${ivyEnabled ? 'R3InjectorError' : 'StaticInjectorError'}(DynamicTestModule)[SomeService -> Dep]: \n` +
|
||||
`${
|
||||
ivyEnabled ?
|
||||
'R3InjectorError' :
|
||||
'StaticInjectorError'}(DynamicTestModule)[SomeService -> Dep]: \n` +
|
||||
' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' +
|
||||
' NullInjectorError: No provider for Dep!');
|
||||
});
|
||||
@ -187,7 +202,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
directiveDef(1, NodeFlags.None, null, 0, SomeService, ['nonExistingDep'])
|
||||
])))
|
||||
.toThrowError(
|
||||
`${ivyEnabled ? 'R3InjectorError' : 'StaticInjectorError'}(DynamicTestModule)[nonExistingDep]: \n` +
|
||||
`${
|
||||
ivyEnabled ? 'R3InjectorError' :
|
||||
'StaticInjectorError'}(DynamicTestModule)[nonExistingDep]: \n` +
|
||||
' StaticInjectorError(Platform: core)[nonExistingDep]: \n' +
|
||||
' NullInjectorError: No provider for nonExistingDep!');
|
||||
});
|
||||
@ -196,8 +213,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
createAndGetRootNodes(compViewDef([
|
||||
elementDef(0, NodeFlags.None, null, null, 1, 'span'),
|
||||
directiveDef(
|
||||
1, NodeFlags.None, null, 0, SomeService,
|
||||
[[DepFlags.Optional, 'nonExistingDep']])
|
||||
1, NodeFlags.None, null, 0, SomeService, [[DepFlags.Optional, 'nonExistingDep']])
|
||||
]));
|
||||
expect(instance.dep).toBe(null);
|
||||
});
|
||||
@ -295,22 +311,21 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
|
||||
expect(instance.dep.createElement).toBeTruthy();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('data binding', () => {
|
||||
|
||||
ARG_TYPE_VALUES.forEach((inlineDynamic) => {
|
||||
it(`should update via strategy ${inlineDynamic}`, () => {
|
||||
let instance: SomeService = undefined !;
|
||||
let instance: SomeService = undefined!;
|
||||
|
||||
class SomeService {
|
||||
a: any;
|
||||
b: any;
|
||||
constructor() { instance = this; }
|
||||
constructor() {
|
||||
instance = this;
|
||||
}
|
||||
}
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
@ -331,7 +346,6 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
const el = rootNodes[0];
|
||||
expect(el.getAttribute('ng-reflect-a')).toBe('v1');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@ -376,7 +390,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(
|
||||
0, NodeFlags.None, null, null, 1, 'span', null, null, null,
|
||||
() => { throw new Error('Test'); }),
|
||||
() => {
|
||||
throw new Error('Test');
|
||||
}),
|
||||
directiveDef(
|
||||
1, NodeFlags.None, null, 0, SomeService, [], null, {emitter: 'someEventName'})
|
||||
]));
|
||||
@ -397,18 +413,37 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
let log: string[] = [];
|
||||
|
||||
class SomeService implements OnInit, DoCheck, OnChanges, AfterContentInit,
|
||||
AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy {
|
||||
AfterContentChecked, AfterViewInit, AfterViewChecked,
|
||||
OnDestroy {
|
||||
id: number;
|
||||
a: any;
|
||||
ngOnInit() { log.push(`${this.id}_ngOnInit`); }
|
||||
ngDoCheck() { log.push(`${this.id}_ngDoCheck`); }
|
||||
ngOnChanges() { log.push(`${this.id}_ngOnChanges`); }
|
||||
ngAfterContentInit() { log.push(`${this.id}_ngAfterContentInit`); }
|
||||
ngAfterContentChecked() { log.push(`${this.id}_ngAfterContentChecked`); }
|
||||
ngAfterViewInit() { log.push(`${this.id}_ngAfterViewInit`); }
|
||||
ngAfterViewChecked() { log.push(`${this.id}_ngAfterViewChecked`); }
|
||||
ngOnDestroy() { log.push(`${this.id}_ngOnDestroy`); }
|
||||
constructor() { this.id = instanceCount++; }
|
||||
ngOnInit() {
|
||||
log.push(`${this.id}_ngOnInit`);
|
||||
}
|
||||
ngDoCheck() {
|
||||
log.push(`${this.id}_ngDoCheck`);
|
||||
}
|
||||
ngOnChanges() {
|
||||
log.push(`${this.id}_ngOnChanges`);
|
||||
}
|
||||
ngAfterContentInit() {
|
||||
log.push(`${this.id}_ngAfterContentInit`);
|
||||
}
|
||||
ngAfterContentChecked() {
|
||||
log.push(`${this.id}_ngAfterContentChecked`);
|
||||
}
|
||||
ngAfterViewInit() {
|
||||
log.push(`${this.id}_ngAfterViewInit`);
|
||||
}
|
||||
ngAfterViewChecked() {
|
||||
log.push(`${this.id}_ngAfterViewChecked`);
|
||||
}
|
||||
ngOnDestroy() {
|
||||
log.push(`${this.id}_ngOnDestroy`);
|
||||
}
|
||||
constructor() {
|
||||
this.id = instanceCount++;
|
||||
}
|
||||
}
|
||||
|
||||
const allFlags = NodeFlags.OnInit | NodeFlags.DoCheck | NodeFlags.OnChanges |
|
||||
@ -479,7 +514,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
directiveDef(
|
||||
1, NodeFlags.OnChanges, null, 0, SomeService, [], {a: [0, 'nonMinifiedA']})
|
||||
],
|
||||
(check, view) => { check(view, 1, ArgumentType.Inline, currValue); }));
|
||||
(check, view) => {
|
||||
check(view, 1, ArgumentType.Inline, currValue);
|
||||
}));
|
||||
|
||||
Services.checkAndUpdateView(view);
|
||||
expect(changesLog).toEqual([new SimpleChange(undefined, 'v1', true)]);
|
||||
@ -492,7 +529,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
|
||||
it('should add a DebugContext to errors in provider afterXXX lifecycles', () => {
|
||||
class SomeService implements AfterContentChecked {
|
||||
ngAfterContentChecked() { throw new Error('Test'); }
|
||||
ngAfterContentChecked() {
|
||||
throw new Error('Test');
|
||||
}
|
||||
}
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
@ -515,7 +554,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR
|
||||
|
||||
it('should add a DebugContext to errors inServices.destroyView', () => {
|
||||
class SomeService implements OnDestroy {
|
||||
ngOnDestroy() { throw new Error('Test'); }
|
||||
ngOnDestroy() {
|
||||
throw new Error('Test');
|
||||
}
|
||||
}
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
|
||||
|
@ -7,19 +7,17 @@
|
||||
*/
|
||||
|
||||
import {PipeTransform} from '@angular/core';
|
||||
import {NodeFlags, Services, asProviderData, directiveDef, elementDef, nodeValue, pipeDef, pureArrayDef, pureObjectDef, purePipeDef} from '@angular/core/src/view/index';
|
||||
import {asProviderData, directiveDef, elementDef, NodeFlags, nodeValue, pipeDef, pureArrayDef, pureObjectDef, purePipeDef, Services} from '@angular/core/src/view/index';
|
||||
|
||||
import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes} from './helper';
|
||||
|
||||
{
|
||||
describe(`View Pure Expressions`, () => {
|
||||
|
||||
class Service {
|
||||
data: any;
|
||||
}
|
||||
|
||||
describe('pure arrays', () => {
|
||||
|
||||
ARG_TYPE_VALUES.forEach((inlineDynamic) => {
|
||||
it(`should update via strategy ${inlineDynamic}`, () => {
|
||||
let values: any[];
|
||||
@ -52,9 +50,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot
|
||||
expect(arr1).not.toBe(arr0);
|
||||
expect(arr1).toEqual([3, 2]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('pure objects', () => {
|
||||
@ -90,7 +86,6 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot
|
||||
expect(obj1).not.toBe(obj0);
|
||||
expect(obj1).toEqual({a: 3, b: 2});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@ -98,14 +93,16 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot
|
||||
ARG_TYPE_VALUES.forEach((inlineDynamic) => {
|
||||
it(`should update via strategy ${inlineDynamic}`, () => {
|
||||
class SomePipe implements PipeTransform {
|
||||
transform(v1: any, v2: any) { return [v1 + 10, v2 + 20]; }
|
||||
transform(v1: any, v2: any) {
|
||||
return [v1 + 10, v2 + 20];
|
||||
}
|
||||
}
|
||||
|
||||
let values: any[];
|
||||
|
||||
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
|
||||
[
|
||||
elementDef(0, NodeFlags.None, null !, null !, 3, 'span'),
|
||||
elementDef(0, NodeFlags.None, null!, null!, 3, 'span'),
|
||||
pipeDef(NodeFlags.None, SomePipe, []),
|
||||
purePipeDef(2, 2),
|
||||
directiveDef(3, NodeFlags.None, null, 0, Service, [], {data: [0, 'data']}),
|
||||
@ -133,7 +130,6 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot
|
||||
expect(obj1).not.toBe(obj0);
|
||||
expect(obj1).toEqual([13, 22]);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -8,20 +8,19 @@
|
||||
|
||||
import {ElementRef, QueryList, TemplateRef, ViewContainerRef} from '@angular/core';
|
||||
import {getDebugContext} from '@angular/core/src/errors';
|
||||
import {NodeDef, NodeFlags, QueryBindingType, QueryValueType, Services, anchorDef, asElementData, asProviderData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, queryDef} from '@angular/core/src/view/index';
|
||||
import {anchorDef, asElementData, asProviderData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, NodeDef, NodeFlags, QueryBindingType, queryDef, QueryValueType, Services} from '@angular/core/src/view/index';
|
||||
|
||||
import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedView} from './helper';
|
||||
|
||||
{
|
||||
describe(`Query Views`, () => {
|
||||
|
||||
const someQueryId = 1;
|
||||
|
||||
class AService {}
|
||||
|
||||
class QueryService {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
a !: QueryList<AService>;
|
||||
a!: QueryList<AService>;
|
||||
}
|
||||
|
||||
function contentQueryProviders(checkIndex: number) {
|
||||
@ -47,7 +46,15 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
...nodes
|
||||
])),
|
||||
directiveDef(
|
||||
checkIndex + 1, NodeFlags.Component, null !, 0, QueryService, [], null !, null !, ),
|
||||
checkIndex + 1,
|
||||
NodeFlags.Component,
|
||||
null!,
|
||||
0,
|
||||
QueryService,
|
||||
[],
|
||||
null!,
|
||||
null!,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@ -60,7 +67,6 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
}
|
||||
|
||||
describe('content queries', () => {
|
||||
|
||||
it('should query providers on the same element and child elements', () => {
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(0, NodeFlags.None, null, null, 5, 'div'),
|
||||
@ -77,12 +83,11 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
|
||||
const as = qs.a.toArray();
|
||||
expect(as.length).toBe(2);
|
||||
expect(as[0]).toBe(asProviderData(view, 3).instance);
|
||||
expect(as[1]).toBe(asProviderData(view, 5).instance);
|
||||
expect(as [0]).toBe(asProviderData(view, 3).instance);
|
||||
expect(as [1]).toBe(asProviderData(view, 5).instance);
|
||||
});
|
||||
|
||||
it('should not query providers on sibling or parent elements', () => {
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
elementDef(0, NodeFlags.None, null, null, 6, 'div'),
|
||||
aServiceProvider(1),
|
||||
@ -249,7 +254,7 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
it('should query all matches', () => {
|
||||
class QueryService {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
a !: QueryList<AService>;
|
||||
a!: QueryList<AService>;
|
||||
}
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
@ -275,7 +280,7 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
it('should query the first match', () => {
|
||||
class QueryService {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
a !: AService;
|
||||
a!: AService;
|
||||
}
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
@ -299,7 +304,7 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
it('should query ElementRef', () => {
|
||||
class QueryService {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
a !: ElementRef;
|
||||
a!: ElementRef;
|
||||
}
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
@ -319,7 +324,7 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
it('should query TemplateRef', () => {
|
||||
class QueryService {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
a !: TemplateRef<any>;
|
||||
a!: TemplateRef<any>;
|
||||
}
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
@ -341,7 +346,7 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
it('should query ViewContainerRef', () => {
|
||||
class QueryService {
|
||||
// TODO(issue/24571): remove '!'.
|
||||
a !: ViewContainerRef;
|
||||
a!: ViewContainerRef;
|
||||
}
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
@ -363,7 +368,9 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi
|
||||
describe('general binding behavior', () => {
|
||||
it('should report debug info on binding errors', () => {
|
||||
class QueryService {
|
||||
set a(value: any) { throw new Error('Test'); }
|
||||
set a(value: any) {
|
||||
throw new Error('Test');
|
||||
}
|
||||
}
|
||||
|
||||
const {view} = createAndGetRootNodes(compViewDef([
|
||||
|
@ -6,13 +6,12 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {DebugContext, NodeFlags, QueryValueType, Services, asElementData, asTextData, directiveDef, elementDef, textDef} from '@angular/core/src/view/index';
|
||||
import {asElementData, asTextData, DebugContext, directiveDef, elementDef, NodeFlags, QueryValueType, Services, textDef} from '@angular/core/src/view/index';
|
||||
|
||||
import {compViewDef, createAndGetRootNodes} from './helper';
|
||||
|
||||
{
|
||||
describe('View Services', () => {
|
||||
|
||||
describe('DebugContext', () => {
|
||||
class AComp {}
|
||||
|
||||
|
@ -8,13 +8,12 @@
|
||||
|
||||
import {ɵgetDOM as getDOM} from '@angular/common';
|
||||
import {getDebugNode} from '@angular/core';
|
||||
import {NodeFlags, Services, asTextData, elementDef, textDef} from '@angular/core/src/view/index';
|
||||
import {asTextData, elementDef, NodeFlags, Services, textDef} from '@angular/core/src/view/index';
|
||||
|
||||
import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes} from './helper';
|
||||
|
||||
{
|
||||
describe(`View Text`, () => {
|
||||
|
||||
describe('create', () => {
|
||||
it('should create text nodes without parents', () => {
|
||||
const rootNodes = createAndGetRootNodes(compViewDef([textDef(0, null, ['a'])])).rootNodes;
|
||||
@ -44,7 +43,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot
|
||||
const someContext = {};
|
||||
const {view, rootNodes} =
|
||||
createAndGetRootNodes(compViewDef([textDef(0, null, ['a'])]), someContext);
|
||||
expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asTextData(view, 0).renderText);
|
||||
expect(getDebugNode(rootNodes[0])!.nativeNode).toBe(asTextData(view, 0).renderText);
|
||||
});
|
||||
});
|
||||
|
||||
@ -55,7 +54,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot
|
||||
[
|
||||
textDef(0, null, ['0', '1', '2']),
|
||||
],
|
||||
null !, (check, view) => {
|
||||
null!, (check, view) => {
|
||||
checkNodeInlineOrDynamic(check, view, 0, inlineDynamic, ['a', 'b']);
|
||||
}));
|
||||
|
||||
@ -63,9 +62,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot
|
||||
|
||||
expect(rootNodes[0].textContent).toBe('0a1b2');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -6,14 +6,13 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NodeFlags, QueryValueType, ViewDefinition, ViewFlags, anchorDef, directiveDef, elementDef, textDef, viewDef} from '@angular/core/src/view/index';
|
||||
import {anchorDef, directiveDef, elementDef, NodeFlags, QueryValueType, textDef, viewDef, ViewDefinition, ViewFlags} from '@angular/core/src/view/index';
|
||||
import {filterQueryId} from '@angular/core/src/view/util';
|
||||
|
||||
{
|
||||
describe('viewDef', () => {
|
||||
|
||||
describe('parent', () => {
|
||||
function parents(viewDef: ViewDefinition): (number | null)[] {
|
||||
function parents(viewDef: ViewDefinition): (number|null)[] {
|
||||
return viewDef.nodes.map(node => node.parent ? node.parent.nodeIndex : null);
|
||||
}
|
||||
|
||||
@ -54,7 +53,6 @@ import {filterQueryId} from '@angular/core/src/view/util';
|
||||
});
|
||||
|
||||
describe('childFlags', () => {
|
||||
|
||||
function childFlags(viewDef: ViewDefinition): number[] {
|
||||
return viewDef.nodes.map(node => node.childFlags);
|
||||
}
|
||||
@ -122,7 +120,7 @@ import {filterQueryId} from '@angular/core/src/view/util';
|
||||
const vd = viewDef(ViewFlags.None, [
|
||||
elementDef(0, NodeFlags.None, null, null, 2, 'span'),
|
||||
elementDef(1, NodeFlags.None, null, null, 1, 'span'),
|
||||
directiveDef(2, NodeFlags.AfterContentChecked, null !, 0, AService, []),
|
||||
directiveDef(2, NodeFlags.AfterContentChecked, null!, 0, AService, []),
|
||||
elementDef(3, NodeFlags.None, null, null, 2, 'span'),
|
||||
directiveDef(4, NodeFlags.AfterContentInit, null, 0, AService, []),
|
||||
directiveDef(5, NodeFlags.AfterViewInit, null, 0, AService, []),
|
||||
|
Reference in New Issue
Block a user