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:
Miško Hevery
2019-10-28 12:08:17 -07:00
committed by Andrew Scott
parent 7bccef516f
commit 4924d73b8e
22 changed files with 227 additions and 62 deletions

View File

@ -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/);

View 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');
});
});
});