feat(ivy): expose a series of helpful application inspection tools (#25919)
PR Close #25919
This commit is contained in:
parent
cf095d982d
commit
0c344715e5
|
@ -3,13 +3,13 @@
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "ng build --prod --progress false",
|
"build": "ng build --prod --progress=false",
|
||||||
"e2e": "ng e2e",
|
"e2e": "ng e2e",
|
||||||
"lint": "ng lint",
|
"lint": "ng lint",
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"postinstall": "webdriver-manager update --gecko false --standalone false $CHROMEDRIVER_VERSION_ARG",
|
"postinstall": "webdriver-manager update --gecko=false --standalone=false $CHROMEDRIVER_VERSION_ARG",
|
||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
"test": "ng test && ng e2e --webdriver-update=false && ng e2e --prod --webdriver-update=false"
|
"test": "ng test --progress=false && ng e2e --webdriver-update=false && ng e2e --prod --webdriver-update=false"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "~0.5.0",
|
"@angular-devkit/build-angular": "~0.5.0",
|
||||||
"@angular/cli": "^6.0.0-rc.5",
|
"@angular/cli": "7.0.0-beta.4",
|
||||||
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
"@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli",
|
||||||
"@angular/language-service": "file:../../dist/packages-dist/language-service",
|
"@angular/language-service": "file:../../dist/packages-dist/language-service",
|
||||||
"@types/jasmine": "~2.8.3",
|
"@types/jasmine": "~2.8.3",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -352,7 +352,8 @@ function getLNodeFromViewData(lViewData: LViewData, lElementIndex: number): LEle
|
||||||
* Returns a collection of directive index values that are used on the element
|
* Returns a collection of directive index values that are used on the element
|
||||||
* (which is referenced by the lNodeIndex)
|
* (which is referenced by the lNodeIndex)
|
||||||
*/
|
*/
|
||||||
function discoverDirectiveIndices(lViewData: LViewData, lNodeIndex: number): number[]|null {
|
export function discoverDirectiveIndices(
|
||||||
|
lViewData: LViewData, lNodeIndex: number, includeComponents?: boolean): number[]|null {
|
||||||
const directivesAcrossView = lViewData[DIRECTIVES];
|
const directivesAcrossView = lViewData[DIRECTIVES];
|
||||||
const tNode = lViewData[TVIEW].data[lNodeIndex] as TNode;
|
const tNode = lViewData[TVIEW].data[lNodeIndex] as TNode;
|
||||||
if (directivesAcrossView && directivesAcrossView.length) {
|
if (directivesAcrossView && directivesAcrossView.length) {
|
||||||
|
@ -373,12 +374,20 @@ function discoverDirectiveIndices(lViewData: LViewData, lNodeIndex: number): num
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function discoverDirectives(lViewData: LViewData, directiveIndices: number[]): number[]|null {
|
/**
|
||||||
|
* Returns a list of directives extracted from the given view based on the
|
||||||
|
* provided list of directive index values.
|
||||||
|
*
|
||||||
|
* @param lViewData The target view data
|
||||||
|
* @param indices A collection of directive index values which will be used to
|
||||||
|
* figure out the directive instances
|
||||||
|
*/
|
||||||
|
export function discoverDirectives(lViewData: LViewData, indices: number[]): number[]|null {
|
||||||
const directives: any[] = [];
|
const directives: any[] = [];
|
||||||
const directiveInstances = lViewData[DIRECTIVES];
|
const directiveInstances = lViewData[DIRECTIVES];
|
||||||
if (directiveInstances) {
|
if (directiveInstances) {
|
||||||
for (let i = 0; i < directiveIndices.length; i++) {
|
for (let i = 0; i < indices.length; i++) {
|
||||||
const directiveIndex = directiveIndices[i];
|
const directiveIndex = indices[i];
|
||||||
const directive = directiveInstances[directiveIndex];
|
const directive = directiveInstances[directiveIndex];
|
||||||
directives.push(directive);
|
directives.push(directive);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
/**
|
||||||
|
* @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 {Injector} from '../di/injector';
|
||||||
|
|
||||||
|
import {assertDefined} from './assert';
|
||||||
|
import {LContext, discoverDirectiveIndices, discoverDirectives, getContext, isComponentInstance, readPatchedLViewData} from './context_discovery';
|
||||||
|
import {LElementNode, TNode, TNodeFlags} from './interfaces/node';
|
||||||
|
import {CONTEXT, FLAGS, INJECTOR, LViewData, LViewFlags, PARENT, RootContext, TVIEW} from './interfaces/view';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOTE: The following functions might not be ideal for core usage in Angular...
|
||||||
|
*
|
||||||
|
* Each function below is designed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the component instance associated with the target.
|
||||||
|
*
|
||||||
|
* If a DOM is used then it will return the component that
|
||||||
|
* owns the view where the element is situated.
|
||||||
|
* If a component instance is used then it will return the
|
||||||
|
* instance of the parent component depending on where
|
||||||
|
* the component instance is exists in a template.
|
||||||
|
* If a directive instance is used then it will return the
|
||||||
|
* component that contains that directive in it's template.
|
||||||
|
*/
|
||||||
|
export function getComponent<T = {}>(target: {}): T|null {
|
||||||
|
const context = loadContext(target) !;
|
||||||
|
|
||||||
|
if (context.component === undefined) {
|
||||||
|
let lViewData = context.lViewData;
|
||||||
|
while (lViewData) {
|
||||||
|
const ctx = lViewData ![CONTEXT] !as{};
|
||||||
|
if (ctx && isComponentInstance(ctx)) {
|
||||||
|
context.component = ctx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lViewData = lViewData ![PARENT] !;
|
||||||
|
}
|
||||||
|
if (context.component === undefined) {
|
||||||
|
context.component = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.component as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the host component instance associated with the target.
|
||||||
|
*
|
||||||
|
* This will only return a component instance of the DOM node
|
||||||
|
* contains an instance of a component on it.
|
||||||
|
*/
|
||||||
|
export function getHostComponent<T = {}>(target: {}): T|null {
|
||||||
|
const context = loadContext(target);
|
||||||
|
const tNode = context.lViewData[TVIEW].data[context.lNodeIndex] as TNode;
|
||||||
|
if (tNode.flags & TNodeFlags.isComponent) {
|
||||||
|
const lNode = context.lViewData[context.lNodeIndex] as LElementNode;
|
||||||
|
return lNode.data ![CONTEXT] as any as T;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the `RootContext` instance that is associated with
|
||||||
|
* the application where the target is situated.
|
||||||
|
*/
|
||||||
|
export function getRootContext(target: {}): RootContext {
|
||||||
|
const context = loadContext(target) !;
|
||||||
|
const rootLViewData = getRootView(context.lViewData);
|
||||||
|
return rootLViewData[CONTEXT] as RootContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all the components in the application
|
||||||
|
* that are have been bootstrapped.
|
||||||
|
*/
|
||||||
|
export function getRootComponents(target: {}): any[] {
|
||||||
|
return [...getRootContext(target).components];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the injector instance that is associated with
|
||||||
|
* the element, component or directive.
|
||||||
|
*/
|
||||||
|
export function getInjector(target: {}): Injector|null {
|
||||||
|
const context = loadContext(target) !;
|
||||||
|
return context.lViewData[INJECTOR] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all the directives that are associated
|
||||||
|
* with the underlying target element.
|
||||||
|
*/
|
||||||
|
export function getDirectives(target: {}): Array<{}> {
|
||||||
|
const context = loadContext(target) !;
|
||||||
|
|
||||||
|
if (context.directives === undefined) {
|
||||||
|
context.directiveIndices = discoverDirectiveIndices(context.lViewData, context.lNodeIndex);
|
||||||
|
context.directives = context.directiveIndices ?
|
||||||
|
discoverDirectives(context.lViewData, context.directiveIndices) :
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.directives || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadContext(target: {}): LContext {
|
||||||
|
const context = getContext(target);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(
|
||||||
|
ngDevMode ? 'Unable to find the given context data for the given target' :
|
||||||
|
'Invalid ng target');
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the root view from any component by walking the parent `LViewData` until
|
||||||
|
* reaching the root `LViewData`.
|
||||||
|
*
|
||||||
|
* @param componentOrView any component or view
|
||||||
|
*/
|
||||||
|
export function getRootView(componentOrView: LViewData | {}): LViewData {
|
||||||
|
let lViewData: LViewData;
|
||||||
|
if (Array.isArray(componentOrView)) {
|
||||||
|
ngDevMode && assertDefined(componentOrView, 'lViewData');
|
||||||
|
lViewData = componentOrView as LViewData;
|
||||||
|
} else {
|
||||||
|
ngDevMode && assertDefined(componentOrView, 'component');
|
||||||
|
lViewData = readPatchedLViewData(componentOrView) !;
|
||||||
|
}
|
||||||
|
while (lViewData && !(lViewData[FLAGS] & LViewFlags.IsRoot)) {
|
||||||
|
lViewData = lViewData[PARENT] !;
|
||||||
|
}
|
||||||
|
return lViewData;
|
||||||
|
}
|
|
@ -11,9 +11,9 @@ import './ng_dev_mode';
|
||||||
import {QueryList} from '../linker';
|
import {QueryList} from '../linker';
|
||||||
import {Sanitizer} from '../sanitization/security';
|
import {Sanitizer} from '../sanitization/security';
|
||||||
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
||||||
|
|
||||||
import {assertDefined, assertEqual, assertLessThan, assertNotEqual} from './assert';
|
import {assertDefined, assertEqual, assertLessThan, assertNotEqual} from './assert';
|
||||||
import {attachPatchData, getLElementFromComponent, readElementValue, readPatchedLViewData} from './context_discovery';
|
import {attachPatchData, getLElementFromComponent, readElementValue, readPatchedLViewData} from './context_discovery';
|
||||||
|
import {getRootView} from './discovery_utils';
|
||||||
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
|
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
|
||||||
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
|
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
|
||||||
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
|
import {ACTIVE_INDEX, LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
|
||||||
|
@ -28,9 +28,7 @@ import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||||
import {appendChild, appendProjectedNode, createTextNode, findComponentView, getContainerNode, getHostElementNode, getLViewChild, getParentOrContainerNode, getRenderParent, insertView, removeView} from './node_manipulation';
|
import {appendChild, appendProjectedNode, createTextNode, findComponentView, getContainerNode, getHostElementNode, getLViewChild, getParentOrContainerNode, getRenderParent, insertView, removeView} from './node_manipulation';
|
||||||
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
||||||
import {StylingContext, allocStylingContext, createStylingContextTemplate, renderStyling as renderElementStyles, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling';
|
import {StylingContext, allocStylingContext, createStylingContextTemplate, renderStyling as renderElementStyles, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling';
|
||||||
import {assertDataInRangeInternal, getLNode, getRootContext, getRootView, isContentQueryHost, isDifferent, loadElementInternal, loadInternal, stringify} from './util';
|
import {assertDataInRangeInternal, getLNode, isContentQueryHost, isDifferent, loadElementInternal, loadInternal, stringify} from './util';
|
||||||
import {ViewRef} from './view_ref';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -654,10 +654,10 @@
|
||||||
"name": "getRendererFactory"
|
"name": "getRendererFactory"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getRootContext"
|
"name": "getRootContext$1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getRootView"
|
"name": "getRootView$1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "getStyleSanitizer"
|
"name": "getStyleSanitizer"
|
||||||
|
|
|
@ -0,0 +1,269 @@
|
||||||
|
/**
|
||||||
|
* @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 {StaticInjector} from '../../src/di/injector';
|
||||||
|
import {getComponent, getDirectives, getHostComponent, getInjector, getRootComponents} from '../../src/render3/discovery_utils';
|
||||||
|
import {RenderFlags, defineComponent, defineDirective} from '../../src/render3/index';
|
||||||
|
import {element} from '../../src/render3/instructions';
|
||||||
|
|
||||||
|
import {ComponentFixture} from './render_util';
|
||||||
|
|
||||||
|
describe('discovery utils', () => {
|
||||||
|
describe('getComponent()', () => {
|
||||||
|
it('should return the component instance for a DOM element', () => {
|
||||||
|
class InnerComp {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: InnerComp,
|
||||||
|
selectors: [['inner-comp']],
|
||||||
|
factory: () => new InnerComp(),
|
||||||
|
consts: 1,
|
||||||
|
vars: 0,
|
||||||
|
template: (rf: RenderFlags, ctx: InnerComp) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
element(0, 'div');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class Comp {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: Comp,
|
||||||
|
selectors: [['comp']],
|
||||||
|
factory: () => new Comp(),
|
||||||
|
consts: 1,
|
||||||
|
vars: 0,
|
||||||
|
template: (rf: RenderFlags, ctx: Comp) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
element(0, 'inner-comp');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
directives: [InnerComp]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fixture = new ComponentFixture(Comp);
|
||||||
|
fixture.update();
|
||||||
|
|
||||||
|
const hostElm = fixture.hostElement;
|
||||||
|
const innerCompElm = hostElm.querySelector('inner-comp');
|
||||||
|
const component = fixture.component;
|
||||||
|
|
||||||
|
expect(getComponent(innerCompElm !) !).toBe(component);
|
||||||
|
expect(getComponent(hostElm) !).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getRootComponents()', () => {
|
||||||
|
it('should return a list of the root components of the application from an element', () => {
|
||||||
|
let innerComp: InnerComp;
|
||||||
|
|
||||||
|
class InnerComp {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: InnerComp,
|
||||||
|
selectors: [['inner-comp']],
|
||||||
|
factory: () => innerComp = new InnerComp(),
|
||||||
|
consts: 1,
|
||||||
|
vars: 0,
|
||||||
|
template: (rf: RenderFlags, ctx: InnerComp) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
element(0, 'div');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class Comp {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: Comp,
|
||||||
|
selectors: [['comp']],
|
||||||
|
factory: () => new Comp(),
|
||||||
|
consts: 1,
|
||||||
|
vars: 0,
|
||||||
|
template: (rf: RenderFlags, ctx: Comp) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
element(0, 'inner-comp');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
directives: [InnerComp]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fixture = new ComponentFixture(Comp);
|
||||||
|
fixture.update();
|
||||||
|
|
||||||
|
const hostElm = fixture.hostElement;
|
||||||
|
const innerElm = hostElm.querySelector('inner-comp') !;
|
||||||
|
const divElm = hostElm.querySelector('div') !;
|
||||||
|
const component = fixture.component;
|
||||||
|
|
||||||
|
expect(getRootComponents(hostElm) !).toEqual([component]);
|
||||||
|
expect(getRootComponents(innerElm) !).toEqual([component]);
|
||||||
|
expect(getRootComponents(divElm) !).toEqual([component]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getDirectives()', () => {
|
||||||
|
it('should return a list of the directives that are on the given element', () => {
|
||||||
|
let myDir1Instance: MyDir1|null = null;
|
||||||
|
let myDir2Instance: MyDir2|null = null;
|
||||||
|
let myDir3Instance: MyDir2|null = null;
|
||||||
|
|
||||||
|
class MyDir1 {
|
||||||
|
static ngDirectiveDef = defineDirective({
|
||||||
|
type: MyDir1,
|
||||||
|
selectors: [['', 'my-dir-1', '']],
|
||||||
|
factory: () => myDir1Instance = new MyDir1()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyDir2 {
|
||||||
|
static ngDirectiveDef = defineDirective({
|
||||||
|
type: MyDir2,
|
||||||
|
selectors: [['', 'my-dir-2', '']],
|
||||||
|
factory: () => myDir2Instance = new MyDir2()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyDir3 {
|
||||||
|
static ngDirectiveDef = defineDirective({
|
||||||
|
type: MyDir3,
|
||||||
|
selectors: [['', 'my-dir-3', '']],
|
||||||
|
factory: () => myDir3Instance = new MyDir2()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class Comp {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: Comp,
|
||||||
|
selectors: [['comp']],
|
||||||
|
factory: () => new Comp(),
|
||||||
|
consts: 2,
|
||||||
|
vars: 0,
|
||||||
|
template: (rf: RenderFlags, ctx: Comp) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
element(0, 'div', ['my-dir-1', '', 'my-dir-2', '']);
|
||||||
|
element(1, 'div', ['my-dir-3']);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
directives: [MyDir1, MyDir2, MyDir3]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fixture = new ComponentFixture(Comp);
|
||||||
|
fixture.update();
|
||||||
|
|
||||||
|
const hostElm = fixture.hostElement;
|
||||||
|
const elements = hostElm.querySelectorAll('div');
|
||||||
|
|
||||||
|
const elm1 = elements[0];
|
||||||
|
const elm1Dirs = getDirectives(elm1);
|
||||||
|
expect(elm1Dirs).toContain(myDir1Instance !);
|
||||||
|
expect(elm1Dirs).toContain(myDir2Instance !);
|
||||||
|
|
||||||
|
const elm2 = elements[1];
|
||||||
|
const elm2Dirs = getDirectives(elm2);
|
||||||
|
expect(elm2Dirs).toContain(myDir3Instance !);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getHostComponent()', () => {
|
||||||
|
it('should return the component instance for a DOM element', () => {
|
||||||
|
let innerComp: InnerComp;
|
||||||
|
|
||||||
|
class InnerComp {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: InnerComp,
|
||||||
|
selectors: [['inner-comp']],
|
||||||
|
factory: () => innerComp = new InnerComp(),
|
||||||
|
consts: 1,
|
||||||
|
vars: 0,
|
||||||
|
template: (rf: RenderFlags, ctx: InnerComp) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
element(0, 'div');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class Comp {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: Comp,
|
||||||
|
selectors: [['comp']],
|
||||||
|
factory: () => new Comp(),
|
||||||
|
consts: 1,
|
||||||
|
vars: 0,
|
||||||
|
template: (rf: RenderFlags, ctx: Comp) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
element(0, 'inner-comp');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
directives: [InnerComp]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fixture = new ComponentFixture(Comp);
|
||||||
|
fixture.update();
|
||||||
|
|
||||||
|
const hostElm = fixture.hostElement;
|
||||||
|
const innerElm = hostElm.querySelector('inner-comp') !;
|
||||||
|
const divElm = hostElm.querySelector('div') !;
|
||||||
|
const component = fixture.component;
|
||||||
|
|
||||||
|
expect(getHostComponent(hostElm) !).toBe(component);
|
||||||
|
expect(getHostComponent(innerElm) !).toBe(innerComp !);
|
||||||
|
expect(getHostComponent(divElm) !).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getInjector()', () => {
|
||||||
|
it('should return the instance of the injector that was passed into the component', () => {
|
||||||
|
class Comp {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: Comp,
|
||||||
|
selectors: [['comp']],
|
||||||
|
factory: () => new Comp(),
|
||||||
|
consts: 1,
|
||||||
|
vars: 0,
|
||||||
|
template: (rf: RenderFlags, ctx: Comp) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
element(0, 'div');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const injector = new StaticInjector([]);
|
||||||
|
const fixture = new ComponentFixture(Comp, {injector});
|
||||||
|
fixture.update();
|
||||||
|
|
||||||
|
expect(getInjector(fixture.hostElement) !).toBe(injector);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return null when there is no injector passed into a component', () => {
|
||||||
|
class Comp {
|
||||||
|
static ngComponentDef = defineComponent({
|
||||||
|
type: Comp,
|
||||||
|
selectors: [['comp']],
|
||||||
|
factory: () => new Comp(),
|
||||||
|
consts: 1,
|
||||||
|
vars: 0,
|
||||||
|
template: (rf: RenderFlags, ctx: Comp) => {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
element(0, 'div');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fixture = new ComponentFixture(Comp);
|
||||||
|
fixture.update();
|
||||||
|
|
||||||
|
expect(getInjector(fixture.hostElement)).toEqual(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue