diff --git a/libs/ng-mocks/src/lib/mock-helper/func.get-from-node-ivy.spec.ts b/libs/ng-mocks/src/lib/mock-helper/func.get-from-node-ivy.spec.ts index 35b6b403dc..8a480dce4a 100644 --- a/libs/ng-mocks/src/lib/mock-helper/func.get-from-node-ivy.spec.ts +++ b/libs/ng-mocks/src/lib/mock-helper/func.get-from-node-ivy.spec.ts @@ -121,4 +121,102 @@ describe('func.get-from-node-ivy', () => { funcGetFromNodeIvy(result, node, Proto); expect(result).toEqual([]); }); + + it('handles root node indexes instead of contexts', () => { + const result: any[] = []; + const proto = new Proto(); + + const lView = []; + lView[1] = {}; + lView[20] = 6; + lView[21] = [proto]; + + const node: any = { + nativeNode: {}, + parent: { + injector: { + _lView: lView, + }, + nativeNode: { + __ngContext__: 6, + }, + }, + }; + + funcGetFromNodeIvy(result, node, Proto); + expect(result).toEqual([proto]); + }); + + it('skips unknown root node indexes', () => { + const result: any[] = []; + + const node: any = { + nativeNode: {}, + parent: { + injector: {}, + nativeNode: { + __ngContext__: 6, + }, + }, + }; + + funcGetFromNodeIvy(result, node, Proto); + expect(result).toEqual([]); + }); + + it('handles child node indexes instead of contexts', () => { + const result: any[] = []; + const proto = new Proto(); + + const lView = []; + lView[1] = {}; + lView[20] = 6; + lView[21] = [proto]; + + const rootLView = []; + rootLView[1] = {}; + rootLView[20] = 0; + rootLView[21] = lView; + + const node: any = { + nativeNode: {}, + parent: { + injector: { + _lView: rootLView, + }, + nativeNode: { + __ngContext__: 6, + }, + }, + }; + + funcGetFromNodeIvy(result, node, Proto); + expect(result).toEqual([proto]); + }); + + it('skips unknown child node with indexes', () => { + const result: any[] = []; + const proto = new Proto(); + + const lView = []; + lView[21] = [proto]; + + const rootLView = []; + rootLView[21] = lView; + + const node: any = { + nativeNode: {}, + parent: { + injector: { + _lView: rootLView, + }, + nativeNode: { + __ngContext__: 6, + }, + }, + }; + + funcGetFromNodeIvy(result, node, Proto); + expect(result).toEqual([]); + }); }); diff --git a/libs/ng-mocks/src/lib/mock-helper/func.get-from-node-ivy.ts b/libs/ng-mocks/src/lib/mock-helper/func.get-from-node-ivy.ts index c3ebb2e5c1..7fe85369c9 100644 --- a/libs/ng-mocks/src/lib/mock-helper/func.get-from-node-ivy.ts +++ b/libs/ng-mocks/src/lib/mock-helper/func.get-from-node-ivy.ts @@ -6,15 +6,40 @@ import { Node } from './func.get-from-node'; import funcGetFromNodeElement from './func.get-from-node-element'; import funcGetFromNodeScan from './func.get-from-node-scan'; +const detectContextByIndex = (rootView: any, index: number) => { + if (typeof rootView[1] === 'object' && rootView[20] === index) { + return rootView; + } + + for (let i = 21; i < rootView.length; i += 1) { + const item = rootView[i]; + if (Array.isArray(item) && typeof item[1] === 'object' && item[20] === index) { + return item; + } + } + + return undefined; +}; + const detectContext = (node: DebugNode): any => { let current = node; let context = current.nativeNode?.__ngContext__; - while (!context && current.parent) { + while (context === undefined && current.parent) { current = current.parent; context = current.nativeNode.__ngContext__; } + if (typeof context !== 'number') { + return context; + } + // welcome to A12 and its optimization + // https://github.com/angular/angular/pull/41358 + + const rootView = (current.injector as any)._lView; + if (Array.isArray(rootView)) { + return detectContextByIndex(rootView, context); + } - return context; + return undefined; }; const contextToNodes = (context: any): any => (Array.isArray(context) ? context : context?.lView);