From 369f03ad7f3132240db938ea2b4de2de2e38c867 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 20 Jun 2025 09:30:01 +0200 Subject: [PATCH] fix(core): unable to retrieve defer blocks in tests when component injects ViewContainerRef (#62156) Fixes that `getDeferBlocks` wasn't accounting for the case where a component might be injecting `ViewContainerRef`. When that happens, an additional wrapper is introduced that needs to be accounted for when traversing the tree. Fixes #62047. PR Close #62156 --- packages/core/src/defer/discovery.ts | 13 ++++++++++--- packages/core/test/defer_fixture_spec.ts | 17 ++++++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/core/src/defer/discovery.ts b/packages/core/src/defer/discovery.ts index 41b7a8d5100..0b1aef663d6 100644 --- a/packages/core/src/defer/discovery.ts +++ b/packages/core/src/defer/discovery.ts @@ -9,7 +9,7 @@ import {CONTAINER_HEADER_OFFSET} from '../render3/interfaces/container'; import {TNode} from '../render3/interfaces/node'; import {isLContainer, isLView} from '../render3/interfaces/type_checks'; -import {HEADER_OFFSET, LView, TVIEW} from '../render3/interfaces/view'; +import {HEADER_OFFSET, HOST, LView, TVIEW} from '../render3/interfaces/view'; import {DehydratedDeferBlock, TDeferBlockDetails} from './interfaces'; import {getTDeferBlockDetails, isTDeferBlockDetails} from './utils'; @@ -46,8 +46,15 @@ export function getDeferBlocks(lView: LView, deferBlocks: DeferBlockDetails[]) { continue; } } - for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) { - getDeferBlocks(lContainer[i] as LView, deferBlocks); + + // The host can be an `LView` if this is the container + // for a component that injects `ViewContainerRef`. + if (isLView(lContainer[HOST])) { + getDeferBlocks(lContainer[HOST], deferBlocks); + } + + for (let j = CONTAINER_HEADER_OFFSET; j < lContainer.length; j++) { + getDeferBlocks(lContainer[j] as LView, deferBlocks); } } else if (isLView(lView[i])) { // This is a component, enter the `getDeferBlocks` recursively. diff --git a/packages/core/test/defer_fixture_spec.ts b/packages/core/test/defer_fixture_spec.ts index 909a16ccf8e..b1a00a2e6c4 100644 --- a/packages/core/test/defer_fixture_spec.ts +++ b/packages/core/test/defer_fixture_spec.ts @@ -7,7 +7,7 @@ */ import {ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID} from '@angular/common'; -import {Component, PLATFORM_ID} from '../src/core'; +import {Component, inject, PLATFORM_ID, ViewContainerRef} from '../src/core'; import {PendingTasksInternal} from '../src/pending_tasks'; import {DeferBlockBehavior, DeferBlockState, TestBed} from '../testing'; import {expect} from '@angular/private/testing/matchers'; @@ -428,4 +428,19 @@ describe('DeferFixture', () => { const fixtures = await deferBlock.getDeferBlocks(); expect(fixtures.length).toBe(1); }); + + it('should resolve defer blocks in components that inject ViewContainerRef', async () => { + @Component({template: '@defer {Hello}'}) + class DeferTestComponent { + viewContainerRef = inject(ViewContainerRef); + } + + TestBed.configureTestingModule({deferBlockBehavior: DeferBlockBehavior.Manual}); + const fixture = TestBed.createComponent(DeferTestComponent); + fixture.detectChanges(); + + const deferBlocks = await fixture.getDeferBlocks(); + expect(deferBlocks.length).toBe(1); + expect(fixture.componentInstance.viewContainerRef).toBeTruthy(); + }); });