test(ivy): Have more descriptive names for LView
(#33449)
When debugging `LView`s it is easy to get lost since all of them have the same name. This change does three things: 1. It makes `TView` have an explicit type: - `Host`: for the top level `TView` for bootstrap - `Component`: for the `TView` which represents components template - `Embedded`: for the `TView` which represents an embedded template 2. It changes the name of `LView` to `LHostView`, `LComponentView`, and `LEmbeddedView` depending on the `TView` type. 3. For `LComponentView` and `LEmbeddedView` we also append the name of of the `context` constructor. The result is that we have `LView`s which are name as: `LComponentView_MyComponent` and `LEmbeddedView_NgIfContext`. The above changes will make it easier to understand the structure of the application when debugging. NOTE: All of these are behind `ngDevMode` and will get removed in production application. PR Close #33449
This commit is contained in:

committed by
Andrew Scott

parent
10583f951d
commit
c25503b142
@ -7,11 +7,13 @@
|
||||
*/
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {Component, Directive, HostBinding, InjectionToken, ViewChild} from '@angular/core';
|
||||
import {isLView} from '@angular/core/src/render3/interfaces/type_checks';
|
||||
import {CONTEXT} from '@angular/core/src/render3/interfaces/view';
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {onlyInIvy} from '@angular/private/testing';
|
||||
|
||||
import {getHostElement, markDirty} from '../../src/render3/index';
|
||||
import {getComponent, getContext, getDebugNode, getDirectives, getInjectionTokens, getInjector, getListeners, getLocalRefs, getRootComponents, getViewComponent, loadLContext} from '../../src/render3/util/discovery_utils';
|
||||
import {getComponent, getComponentLView, getContext, getDebugNode, getDirectives, getInjectionTokens, getInjector, getListeners, getLocalRefs, getRootComponents, getViewComponent, loadLContext} from '../../src/render3/util/discovery_utils';
|
||||
|
||||
onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => {
|
||||
let fixture: ComponentFixture<MyApp>;
|
||||
@ -87,6 +89,20 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getComponentLView', () => {
|
||||
it('should retrieve component LView from element', () => {
|
||||
const childLView = getComponentLView(child[0]);
|
||||
expect(isLView(childLView)).toBe(true);
|
||||
expect(childLView[CONTEXT] instanceof Child).toBe(true);
|
||||
});
|
||||
|
||||
it('should retrieve component LView from component instance', () => {
|
||||
const childLView = getComponentLView(childComponent[0]);
|
||||
expect(isLView(childLView)).toBe(true);
|
||||
expect(childLView[CONTEXT] instanceof Child).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getContext', () => {
|
||||
it('should throw when called on non-element', () => {
|
||||
expect(() => getContext(dirA[0] as any)).toThrowError(/Expecting instance of DOM Node/);
|
||||
|
49
packages/core/test/acceptance/ngdevmode_debug_spec.ts
Normal file
49
packages/core/test/acceptance/ngdevmode_debug_spec.ts
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @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 {CommonModule} from '@angular/common';
|
||||
import {Component} from '@angular/core';
|
||||
import {LView} from '@angular/core/src/render3/interfaces/view';
|
||||
import {getComponentLView, loadLContext} from '@angular/core/src/render3/util/discovery_utils';
|
||||
import {createNamedArrayType} from '@angular/core/src/util/named_array_type';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {onlyInIvy} from '@angular/private/testing';
|
||||
|
||||
const supportsArraySubclassing =
|
||||
createNamedArrayType('SupportsArraySubclassing').name === 'SupportsArraySubclassing';
|
||||
|
||||
onlyInIvy('Debug information exist in ivy only').describe('ngDevMode debug', () => {
|
||||
describe('LViewDebug', () => {
|
||||
supportsArraySubclassing && it('should name LView based on type', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<ul>
|
||||
<li *ngIf="true">item</li>
|
||||
</ul>
|
||||
`
|
||||
})
|
||||
class MyApp {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [MyApp], imports: [CommonModule]});
|
||||
const fixture = TestBed.createComponent(MyApp);
|
||||
const rootLView = loadLContext(fixture.nativeElement).lView;
|
||||
expect(rootLView.constructor.name).toEqual('LRootView');
|
||||
|
||||
const componentLView = getComponentLView(fixture.componentInstance);
|
||||
expect(componentLView.constructor.name).toEqual('LComponentView_MyApp');
|
||||
|
||||
const element: HTMLElement = fixture.nativeElement;
|
||||
fixture.detectChanges();
|
||||
const li = element.querySelector('li') !;
|
||||
const embeddedLView = loadLContext(li).lView;
|
||||
expect(embeddedLView.constructor.name).toEqual('LEmbeddedView_MyApp_li_1');
|
||||
|
||||
});
|
||||
});
|
||||
});
|
@ -354,10 +354,10 @@
|
||||
"name": "getOrCreateNodeInjectorForNode"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateTNode"
|
||||
"name": "getOrCreateTComponentView"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateTView"
|
||||
"name": "getOrCreateTNode"
|
||||
},
|
||||
{
|
||||
"name": "getParentInjectorIndex"
|
||||
|
@ -273,10 +273,10 @@
|
||||
"name": "getOrCreateNodeInjectorForNode"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateTNode"
|
||||
"name": "getOrCreateTComponentView"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateTView"
|
||||
"name": "getOrCreateTNode"
|
||||
},
|
||||
{
|
||||
"name": "getParentInjectorIndex"
|
||||
|
@ -723,10 +723,10 @@
|
||||
"name": "getOrCreateNodeInjectorForNode"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateTNode"
|
||||
"name": "getOrCreateTComponentView"
|
||||
},
|
||||
{
|
||||
"name": "getOrCreateTView"
|
||||
"name": "getOrCreateTNode"
|
||||
},
|
||||
{
|
||||
"name": "getOriginalError"
|
||||
|
@ -16,7 +16,7 @@ import {ɵɵdefineDirective, ɵɵdirectiveInject, ɵɵelement, ɵɵelementEnd,
|
||||
import {TNODE} from '../../src/render3/interfaces/injector';
|
||||
import {TNodeType} from '../../src/render3/interfaces/node';
|
||||
import {isProceduralRenderer} from '../../src/render3/interfaces/renderer';
|
||||
import {LViewFlags, TVIEW} from '../../src/render3/interfaces/view';
|
||||
import {LViewFlags, TVIEW, TViewType} from '../../src/render3/interfaces/view';
|
||||
import {enterView, leaveViewProcessExit} from '../../src/render3/state';
|
||||
|
||||
import {getRendererFactory2} from './imported_renderer2';
|
||||
@ -223,7 +223,7 @@ describe('di', () => {
|
||||
describe('getOrCreateNodeInjector', () => {
|
||||
it('should handle initial undefined state', () => {
|
||||
const contentView = createLView(
|
||||
null, createTView(-1, null, 1, 0, null, null, null, null, null), null,
|
||||
null, createTView(TViewType.Embedded, -1, null, 1, 0, null, null, null, null, null), {},
|
||||
LViewFlags.CheckAlways, null, null, {} as any, {} as any);
|
||||
enterView(contentView, null);
|
||||
try {
|
||||
|
@ -5,6 +5,7 @@
|
||||
* 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 {TViewType} from '@angular/core/src/render3/interfaces/view';
|
||||
import {ɵɵdefineDirective, ɵɵelementEnd, ɵɵelementStart, ɵɵtext} from '../../../../src/render3/index';
|
||||
import {createTNode, createTView} from '../../../../src/render3/instructions/shared';
|
||||
import {RenderFlags} from '../../../../src/render3/interfaces/definition';
|
||||
@ -74,7 +75,7 @@ function testTemplate(rf: RenderFlags, ctx: any) {
|
||||
|
||||
const viewTNode = createTNode(null !, null, TNodeType.View, -1, null, null) as TViewNode;
|
||||
const embeddedTView = createTView(
|
||||
-1, testTemplate, 21, 10, [Tooltip.ɵdir], null, null, null,
|
||||
TViewType.Embedded, -1, testTemplate, 21, 10, [Tooltip.ɵdir], null, null, null,
|
||||
[['position', 'top', 3, 'tooltip']]);
|
||||
|
||||
// create view once so we don't profile first template pass
|
||||
|
@ -5,6 +5,7 @@
|
||||
* 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 {TViewType} from '@angular/core/src/render3/interfaces/view';
|
||||
import {ɵɵelementEnd, ɵɵelementStart} from '../../../../src/render3/instructions/element';
|
||||
import {createTNode, createTView} from '../../../../src/render3/instructions/shared';
|
||||
import {ɵɵtext} from '../../../../src/render3/instructions/text';
|
||||
@ -64,9 +65,10 @@ function testTemplate(rf: RenderFlags, ctx: any) {
|
||||
}
|
||||
|
||||
const viewTNode = createTNode(null !, null, TNodeType.View, -1, null, null) as TViewNode;
|
||||
const embeddedTView = createTView(-1, testTemplate, 21, 0, null, null, null, null, [
|
||||
['name1', 'value1', 'name2', 'value2', 'name3', 'value3', 'name4', 'value4', 'name5', 'value5']
|
||||
]);
|
||||
const embeddedTView = createTView(
|
||||
TViewType.Embedded, -1, testTemplate, 21, 0, null, null, null, null, [[
|
||||
'name1', 'value1', 'name2', 'value2', 'name3', 'value3', 'name4', 'value4', 'name5', 'value5'
|
||||
]]);
|
||||
|
||||
// create view once so we don't profile first template pass
|
||||
createAndRenderLView(null, embeddedTView, viewTNode);
|
||||
|
@ -5,6 +5,7 @@
|
||||
* 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 {TViewType} from '@angular/core/src/render3/interfaces/view';
|
||||
import {ɵɵelementEnd, ɵɵelementStart} from '../../../../src/render3/instructions/element';
|
||||
import {ɵɵlistener} from '../../../../src/render3/instructions/listener';
|
||||
import {createTNode, createTView} from '../../../../src/render3/instructions/shared';
|
||||
@ -75,8 +76,8 @@ function testTemplate(rf: RenderFlags, ctx: any) {
|
||||
}
|
||||
|
||||
const viewTNode = createTNode(null !, null, TNodeType.View, -1, null, null) as TViewNode;
|
||||
const embeddedTView =
|
||||
createTView(-1, testTemplate, 11, 0, null, null, null, null, [[3, 'click', 'input']]);
|
||||
const embeddedTView = createTView(
|
||||
TViewType.Embedded, -1, testTemplate, 11, 0, null, null, null, null, [[3, 'click', 'input']]);
|
||||
|
||||
// create view once so we don't profile first template pass
|
||||
createAndRenderLView(null, embeddedTView, viewTNode);
|
||||
|
@ -5,8 +5,8 @@
|
||||
* 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 {TViewType} from '@angular/core/src/render3/interfaces/view';
|
||||
import {ElementRef, TemplateRef, ViewContainerRef} from '../../../../src/linker';
|
||||
|
||||
import {ɵɵdefineDirective, ɵɵdirectiveInject, ɵɵtemplate} from '../../../../src/render3/index';
|
||||
import {createTNode, createTView} from '../../../../src/render3/instructions/shared';
|
||||
import {RenderFlags} from '../../../../src/render3/interfaces/definition';
|
||||
@ -60,7 +60,8 @@ function testTemplate(rf: RenderFlags, ctx: any) {
|
||||
|
||||
const viewTNode = createTNode(null !, null, TNodeType.View, -1, null, null) as TViewNode;
|
||||
const embeddedTView = createTView(
|
||||
-1, testTemplate, 2, 0, [NgIfLike.ɵdir], null, null, null, [['viewManipulation', '']]);
|
||||
TViewType.Root, -1, testTemplate, 2, 0, [NgIfLike.ɵdir], null, null, null,
|
||||
[['viewManipulation', '']]);
|
||||
|
||||
// create view once so we don't profile first template pass
|
||||
createAndRenderLView(null, embeddedTView, viewTNode);
|
||||
|
@ -9,7 +9,7 @@ import {addToViewTree, createLContainer, createLView, createTNode, createTView,
|
||||
import {ComponentTemplate} from '../../../src/render3/interfaces/definition';
|
||||
import {TAttributes, TNodeType, TViewNode} from '../../../src/render3/interfaces/node';
|
||||
import {RendererFactory3, domRendererFactory3} from '../../../src/render3/interfaces/renderer';
|
||||
import {LView, LViewFlags, TView} from '../../../src/render3/interfaces/view';
|
||||
import {LView, LViewFlags, TView, TViewType} from '../../../src/render3/interfaces/view';
|
||||
import {insertView} from '../../../src/render3/node_manipulation';
|
||||
|
||||
import {MicroBenchmarkRendererFactory} from './noop_renderer';
|
||||
@ -45,7 +45,7 @@ export function setupTestHarness(
|
||||
templateFn: ComponentTemplate<any>| null, decls: number, vars: number, noOfViews: number,
|
||||
embeddedViewContext: any = {}, consts: TAttributes[] | null = null): TestHarness {
|
||||
// Create a root view with a container
|
||||
const hostTView = createTView(-1, null, 1, 0, null, null, null, null, consts);
|
||||
const hostTView = createTView(TViewType.Root, -1, null, 1, 0, null, null, null, null, consts);
|
||||
const tContainerNode = getOrCreateTNode(hostTView, null, 0, TNodeType.Container, null, null);
|
||||
const hostNode = renderer.createElement('div');
|
||||
const hostLView = createLView(
|
||||
@ -58,7 +58,8 @@ export function setupTestHarness(
|
||||
|
||||
|
||||
// create test embedded views
|
||||
const embeddedTView = createTView(-1, templateFn, decls, vars, null, null, null, null, consts);
|
||||
const embeddedTView =
|
||||
createTView(TViewType.Embedded, -1, templateFn, decls, vars, null, null, null, null, consts);
|
||||
const viewTNode = createTNode(hostTView, null, TNodeType.View, -1, null, null) as TViewNode;
|
||||
|
||||
function createEmbeddedLView(): LView {
|
||||
|
@ -12,8 +12,8 @@ import {ElementRef} from '@angular/core/src/linker/element_ref';
|
||||
import {TemplateRef} from '@angular/core/src/linker/template_ref';
|
||||
import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref';
|
||||
import {Renderer2} from '@angular/core/src/render/api';
|
||||
import {createLView, createTView, getOrCreateTNode, getOrCreateTView, renderComponentOrTemplate} from '@angular/core/src/render3/instructions/shared';
|
||||
import {TAttributes, TConstants, TNodeType} from '@angular/core/src/render3/interfaces/node';
|
||||
import {createLView, createTView, getOrCreateTComponentView, getOrCreateTNode, renderComponentOrTemplate} from '@angular/core/src/render3/instructions/shared';
|
||||
import {TConstants, TNodeType} from '@angular/core/src/render3/interfaces/node';
|
||||
import {enterView, getLView} from '@angular/core/src/render3/state';
|
||||
import {stringifyElement} from '@angular/platform-browser/testing/src/browser_util';
|
||||
|
||||
@ -32,13 +32,15 @@ import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveT
|
||||
import {DirectiveDefList, DirectiveDefListOrFactory, DirectiveTypesOrFactory, HostBindingsFunction, PipeDef, PipeDefList, PipeDefListOrFactory, PipeTypesOrFactory} from '../../src/render3/interfaces/definition';
|
||||
import {PlayerHandler} from '../../src/render3/interfaces/player';
|
||||
import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, RendererStyleFlags3, domRendererFactory3} from '../../src/render3/interfaces/renderer';
|
||||
import {HEADER_OFFSET, LView, LViewFlags, T_HOST} from '../../src/render3/interfaces/view';
|
||||
import {HEADER_OFFSET, LView, LViewFlags, TViewType, T_HOST} from '../../src/render3/interfaces/view';
|
||||
import {destroyLView} from '../../src/render3/node_manipulation';
|
||||
import {getRootView} from '../../src/render3/util/view_traversal_utils';
|
||||
import {Sanitizer} from '../../src/sanitization/sanitizer';
|
||||
|
||||
import {getRendererFactory2} from './imported_renderer2';
|
||||
|
||||
|
||||
|
||||
export abstract class BaseFixture {
|
||||
/**
|
||||
* Each fixture creates the following initial DOM structure:
|
||||
@ -254,7 +256,7 @@ export function renderTemplate<T>(
|
||||
const renderer = providedRendererFactory.createRenderer(null, null);
|
||||
|
||||
// We need to create a root view so it's possible to look up the host element through its index
|
||||
const tView = createTView(-1, null, 1, 0, null, null, null, null, null);
|
||||
const tView = createTView(TViewType.Root, -1, null, 1, 0, null, null, null, null, null);
|
||||
const hostLView = createLView(
|
||||
null, tView, {}, LViewFlags.CheckAlways | LViewFlags.IsRoot, null, null,
|
||||
providedRendererFactory, renderer);
|
||||
@ -270,7 +272,7 @@ export function renderTemplate<T>(
|
||||
def.directiveDefs = directives || null;
|
||||
def.pipeDefs = pipes || null;
|
||||
|
||||
const componentTView = getOrCreateTView(def);
|
||||
const componentTView = getOrCreateTComponentView(def);
|
||||
const hostTNode = getOrCreateTNode(tView, hostLView[T_HOST], 0, TNodeType.Element, null, null);
|
||||
hostLView[hostTNode.index] = hostNode;
|
||||
componentView = createLView(
|
||||
|
@ -8,11 +8,12 @@
|
||||
|
||||
import {createLContainer, createLView, createTNode, createTView} from '@angular/core/src/render3/instructions/shared';
|
||||
import {isLContainer, isLView} from '@angular/core/src/render3/interfaces/type_checks';
|
||||
import {TViewType} from '@angular/core/src/render3/interfaces/view';
|
||||
|
||||
describe('view_utils', () => {
|
||||
it('should verify unwrap methods', () => {
|
||||
const div = document.createElement('div');
|
||||
const tView = createTView(0, null, 0, 0, null, null, null, null, null);
|
||||
const tView = createTView(TViewType.Root, 0, null, 0, 0, null, null, null, null, null);
|
||||
const lView = createLView(null, tView, {}, 0, div, null, {} as any, {} as any, null, null);
|
||||
const tNode = createTNode(null !, null, 3, 0, 'div', []);
|
||||
const lContainer = createLContainer(lView, lView, div, tNode, true);
|
||||
|
Reference in New Issue
Block a user