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
This commit is contained in:
Kristiyan Kostadinov
2025-06-20 09:30:01 +02:00
parent 5a11a7946a
commit 369f03ad7f
2 changed files with 26 additions and 4 deletions
+10 -3
View File
@@ -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.
+16 -1
View File
@@ -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();
});
});