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
This commit is contained in:
parent
353368cccd
commit
5651fa3a95
|
@ -358,7 +358,7 @@ export function toDebugNodes(tNode: TNode | null, lView: LView): DebugNode[]|nul
|
||||||
const debugNodes: DebugNode[] = [];
|
const debugNodes: DebugNode[] = [];
|
||||||
let tNodeCursor: TNode|null = tNode;
|
let tNodeCursor: TNode|null = tNode;
|
||||||
while (tNodeCursor) {
|
while (tNodeCursor) {
|
||||||
debugNodes.push(buildDebugNode(tNodeCursor, lView));
|
debugNodes.push(buildDebugNode(tNodeCursor, lView, tNodeCursor.index));
|
||||||
tNodeCursor = tNodeCursor.next;
|
tNodeCursor = tNodeCursor.next;
|
||||||
}
|
}
|
||||||
return debugNodes;
|
return debugNodes;
|
||||||
|
@ -367,8 +367,8 @@ export function toDebugNodes(tNode: TNode | null, lView: LView): DebugNode[]|nul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildDebugNode(tNode: TNode, lView: LView): DebugNode {
|
export function buildDebugNode(tNode: TNode, lView: LView, nodeIndex: number): DebugNode {
|
||||||
const rawValue = lView[tNode.index];
|
const rawValue = lView[nodeIndex];
|
||||||
const native = unwrapRNode(rawValue);
|
const native = unwrapRNode(rawValue);
|
||||||
const componentLViewDebug = toDebug(readLViewValue(rawValue));
|
const componentLViewDebug = toDebug(readLViewValue(rawValue));
|
||||||
const styles = isStylingContext(tNode.styles) ?
|
const styles = isStylingContext(tNode.styles) ?
|
||||||
|
|
|
@ -14,7 +14,8 @@ import {DebugNode, buildDebugNode} from '../instructions/lview_debug';
|
||||||
import {LContext} from '../interfaces/context';
|
import {LContext} from '../interfaces/context';
|
||||||
import {DirectiveDef} from '../interfaces/definition';
|
import {DirectiveDef} from '../interfaces/definition';
|
||||||
import {TElementNode, TNode, TNodeProviderIndexes} from '../interfaces/node';
|
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 {stringifyForError} from './misc_utils';
|
||||||
import {getLViewParent, getRootContext} from './view_traversal_utils';
|
import {getLViewParent, getRootContext} from './view_traversal_utils';
|
||||||
|
@ -357,17 +358,14 @@ export function getDebugNode(element: Node): DebugNode|null {
|
||||||
|
|
||||||
const lContext = loadLContextFromNode(element);
|
const lContext = loadLContextFromNode(element);
|
||||||
const lView = lContext.lView;
|
const lView = lContext.lView;
|
||||||
let nodeIndex = -1;
|
const nodeIndex = lContext.nodeIndex;
|
||||||
for (let i = HEADER_OFFSET; i < lView.length; i++) {
|
|
||||||
if (lView[i] === element) {
|
|
||||||
nodeIndex = i - HEADER_OFFSET;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nodeIndex !== -1) {
|
if (nodeIndex !== -1) {
|
||||||
const tNode = getTNode(nodeIndex, lView);
|
const valueInLView = lView[nodeIndex];
|
||||||
debugNode = buildDebugNode(tNode, lView);
|
// 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;
|
return debugNode;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {CommonModule} from '@angular/common';
|
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 {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
import {onlyInIvy} from '@angular/private/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(parentDebug.native).toBe(parent);
|
||||||
expect(childDebug.native).toBe(child);
|
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: `
|
||||||
|
<child-comp></child-comp>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
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');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue