From bfb399586916a7b6c65db698f6c8c41e967bd22d Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Wed, 11 Sep 2019 13:48:09 -0700 Subject: [PATCH] fix(ivy): DebugNode throws exceptions when querying some properties (#32622) PR Close #32622 --- .../core/src/render3/util/discovery_utils.ts | 28 ++++++++++++++----- packages/core/src/render3/util/view_utils.ts | 2 +- packages/core/test/debug/debug_node_spec.ts | 18 ++++++++++++ 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/packages/core/src/render3/util/discovery_utils.ts b/packages/core/src/render3/util/discovery_utils.ts index 6a253169524d7..55ebdd1eb5172 100644 --- a/packages/core/src/render3/util/discovery_utils.ts +++ b/packages/core/src/render3/util/discovery_utils.ts @@ -42,7 +42,10 @@ import {unwrapRNode} from './view_utils'; * @publicApi */ export function getComponent(element: Element): T|null { - const context = loadLContextFromNode(element); + if (!(element instanceof Node)) throw new Error('Expecting instance of DOM Node'); + const context = loadLContext(element, false); + if (context === null) return null; + if (context.component === undefined) { context.component = getComponentAtNodeIndex(context.nodeIndex, context.lView); @@ -72,7 +75,10 @@ export function getComponent(element: Element): T|null { * @publicApi */ export function getContext(element: Element): T|null { - const context = loadLContextFromNode(element) !; + if (!(element instanceof Node)) throw new Error('Expecting instance of DOM Node'); + const context = loadLContext(element, false); + if (context === null) return null; + return context.lView[CONTEXT] as T; } @@ -97,7 +103,9 @@ export function getContext(element: Element): T|null { * @publicApi */ export function getViewComponent(element: Element | {}): T|null { - const context = loadLContext(element) !; + const context = loadLContext(element, false); + if (context === null) return null; + let lView = context.lView; let parent: LView|null; ngDevMode && assertLView(lView); @@ -129,7 +137,9 @@ export function getRootComponents(target: {}): any[] { * @publicApi */ export function getInjector(target: {}): Injector { - const context = loadLContext(target); + const context = loadLContext(target, false); + if (context === null) return Injector.NULL; + const tNode = context.lView[TVIEW].data[context.nodeIndex] as TElementNode; return new NodeInjector(tNode, context.lView); } @@ -142,7 +152,7 @@ export function getInjector(target: {}): Injector { */ export function getInjectionTokens(element: Element): any[] { const context = loadLContext(element, false); - if (!context) return []; + if (context === null) return []; const lView = context.lView; const tView = lView[TVIEW]; const tNode = tView.data[context.nodeIndex] as TNode; @@ -207,7 +217,8 @@ export function loadLContext(target: {}, throwOnNotFound: boolean = true): LCont * @publicApi */ export function getLocalRefs(target: {}): {[key: string]: any} { - const context = loadLContext(target) !; + const context = loadLContext(target, false); + if (context === null) return {}; if (context.localRefs === undefined) { context.localRefs = discoverLocalRefs(context.lView, context.nodeIndex); @@ -285,7 +296,10 @@ export function isBrowserEvents(listener: Listener): boolean { * @publicApi */ export function getListeners(element: Element): Listener[] { - const lContext = loadLContextFromNode(element); + if (!(element instanceof Node)) throw new Error('Expecting instance of DOM Node'); + const lContext = loadLContext(element, false); + if (lContext === null) return []; + const lView = lContext.lView; const tView = lView[TVIEW]; const lCleanup = lView[CLEANUP]; diff --git a/packages/core/src/render3/util/view_utils.ts b/packages/core/src/render3/util/view_utils.ts index 7e4f48c6a97eb..02492b25944d8 100644 --- a/packages/core/src/render3/util/view_utils.ts +++ b/packages/core/src/render3/util/view_utils.ts @@ -144,7 +144,7 @@ export function getComponentViewByIndex(nodeIndex: number, hostView: LView): LVi */ export function readPatchedData(target: any): LView|LContext|null { ngDevMode && assertDefined(target, 'Target expected'); - return target[MONKEY_PATCH_KEY_NAME]; + return target[MONKEY_PATCH_KEY_NAME] || null; } export function readPatchedLView(target: any): LView|null { diff --git a/packages/core/test/debug/debug_node_spec.ts b/packages/core/test/debug/debug_node_spec.ts index 0b33aa17480dd..b772ab6531e9e 100644 --- a/packages/core/test/debug/debug_node_spec.ts +++ b/packages/core/test/debug/debug_node_spec.ts @@ -639,6 +639,24 @@ class TestCmptWithPropInterpolation { it('when searching for elements by their properties', () => { expect(() => el.query(e => e.properties['any prop'] === 'any value')).not.toThrow(); }); + + it('when searching by componentInstance', + () => { expect(() => el.query(e => e.componentInstance === null)).not.toThrow(); }); + + it('when searching by context', + () => { expect(() => el.query(e => e.context === null)).not.toThrow(); }); + + it('when searching by listeners', + () => { expect(() => el.query(e => e.listeners.length === 0)).not.toThrow(); }); + + it('when searching by references', + () => { expect(() => el.query(e => e.references === null)).not.toThrow(); }); + + it('when searching by providerTokens', + () => { expect(() => el.query(e => e.providerTokens.length === 0)).not.toThrow(); }); + + it('when searching by injector', + () => { expect(() => el.query(e => e.injector === null)).not.toThrow(); }); }); it('DebugElement.queryAll should pick up both elements inserted via the view and through Renderer2',