From 5651fa3a95eaa6e240824ab103c1162c7c6eab01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Niemel=C3=A4?= Date: Thu, 19 Sep 2019 15:01:08 -0700 Subject: [PATCH] fix(ivy): ensure `window.ng.getDebugNode` returns debug info for component elements (#32780) Prior to this patch the `window.ng.getDebugNode` method would fail to return the debug information for an element that is a host element to a component. PR Close #32780 --- .../src/render3/instructions/lview_debug.ts | 6 ++-- .../core/src/render3/util/discovery_utils.ts | 20 +++++------ .../test/acceptance/discover_utils_spec.ts | 36 ++++++++++++++++++- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/packages/core/src/render3/instructions/lview_debug.ts b/packages/core/src/render3/instructions/lview_debug.ts index 062c573b1b..779416cecd 100644 --- a/packages/core/src/render3/instructions/lview_debug.ts +++ b/packages/core/src/render3/instructions/lview_debug.ts @@ -358,7 +358,7 @@ export function toDebugNodes(tNode: TNode | null, lView: LView): DebugNode[]|nul const debugNodes: DebugNode[] = []; let tNodeCursor: TNode|null = tNode; while (tNodeCursor) { - debugNodes.push(buildDebugNode(tNodeCursor, lView)); + debugNodes.push(buildDebugNode(tNodeCursor, lView, tNodeCursor.index)); tNodeCursor = tNodeCursor.next; } return debugNodes; @@ -367,8 +367,8 @@ export function toDebugNodes(tNode: TNode | null, lView: LView): DebugNode[]|nul } } -export function buildDebugNode(tNode: TNode, lView: LView): DebugNode { - const rawValue = lView[tNode.index]; +export function buildDebugNode(tNode: TNode, lView: LView, nodeIndex: number): DebugNode { + const rawValue = lView[nodeIndex]; const native = unwrapRNode(rawValue); const componentLViewDebug = toDebug(readLViewValue(rawValue)); const styles = isStylingContext(tNode.styles) ? diff --git a/packages/core/src/render3/util/discovery_utils.ts b/packages/core/src/render3/util/discovery_utils.ts index 2c2155d599..76740ac515 100644 --- a/packages/core/src/render3/util/discovery_utils.ts +++ b/packages/core/src/render3/util/discovery_utils.ts @@ -14,7 +14,8 @@ import {DebugNode, buildDebugNode} from '../instructions/lview_debug'; import {LContext} from '../interfaces/context'; import {DirectiveDef} from '../interfaces/definition'; import {TElementNode, TNode, TNodeProviderIndexes} from '../interfaces/node'; -import {CLEANUP, CONTEXT, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, TVIEW} from '../interfaces/view'; +import {isLView} from '../interfaces/type_checks'; +import {CLEANUP, CONTEXT, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, TVIEW, T_HOST} from '../interfaces/view'; import {stringifyForError} from './misc_utils'; import {getLViewParent, getRootContext} from './view_traversal_utils'; @@ -357,17 +358,14 @@ export function getDebugNode(element: Node): DebugNode|null { const lContext = loadLContextFromNode(element); const lView = lContext.lView; - let nodeIndex = -1; - for (let i = HEADER_OFFSET; i < lView.length; i++) { - if (lView[i] === element) { - nodeIndex = i - HEADER_OFFSET; - break; - } - } - + const nodeIndex = lContext.nodeIndex; if (nodeIndex !== -1) { - const tNode = getTNode(nodeIndex, lView); - debugNode = buildDebugNode(tNode, lView); + const valueInLView = lView[nodeIndex]; + // this means that value in the lView is a component with its own + // data. In this situation the TNode is not accessed at the same spot. + const tNode = isLView(valueInLView) ? (valueInLView[T_HOST] as TNode) : + getTNode(nodeIndex - HEADER_OFFSET, lView); + debugNode = buildDebugNode(tNode, lView, nodeIndex); } return debugNode; diff --git a/packages/core/test/acceptance/discover_utils_spec.ts b/packages/core/test/acceptance/discover_utils_spec.ts index 90af3ac198..fb356a6e59 100644 --- a/packages/core/test/acceptance/discover_utils_spec.ts +++ b/packages/core/test/acceptance/discover_utils_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {CommonModule} from '@angular/common'; -import {Component, Directive, InjectionToken, ViewChild} from '@angular/core'; +import {Component, Directive, HostBinding, InjectionToken, ViewChild} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {onlyInIvy} from '@angular/private/testing'; @@ -429,5 +429,39 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () => expect(parentDebug.native).toBe(parent); expect(childDebug.native).toBe(child); }); + + it('should be able to pull debug information for a component host element', () => { + @Component({ + selector: 'child-comp', + template: ` + child comp + ` + }) + class ChildComp { + @HostBinding('style') public styles = {width: '200px', height: '400px'}; + } + + @Component({ + template: ` + + ` + }) + class Comp { + } + + TestBed.configureTestingModule({declarations: [Comp, ChildComp]}); + const fixture = TestBed.createComponent(Comp); + fixture.detectChanges(); + + const child = fixture.nativeElement.querySelector('child-comp') !; + const childDebug = getDebugNode(child) !; + + expect(childDebug.native).toBe(child); + expect(childDebug.styles).toBeTruthy(); + + const styles = childDebug.styles !.values; + expect(styles['width']).toEqual('200px'); + expect(styles['height']).toEqual('400px'); + }); }); });