测试@Inject父组件与@ContentChildren联用出现初始化错误排查
问题分析与解决:Angular组件测试循环引用报错
场景说明
开发了一套由父组件CustomTabsComponent和子组件CustomTabComponent组成的自定义标签页组件,运行时无报错,但编写测试代码时抛出Uncaught ReferenceError: Cannot access 'CustomTabComponent' before initialization错误。
组件代码
父组件(CustomTabsComponent)
@Component({ selector: 'app-custom-tabs', template: ` <div class="inline-flex"> <ng-content select="app-custom-tab"></ng-content> </div> ` }) export class CustomTabsComponent { @ContentChildren(CustomTabComponent) _tabs: QueryList<CustomTabComponent>; }
子组件(CustomTabComponent)
@Component({ selector: 'app-custom-tab', template: ` <div> <ng-content></ng-content> </div> ` }) export class CustomTabComponent { constructor(@Inject(CustomTabsComponent) private _group: CustomTabsComponent) { } }
测试代码
@Component({ selector: 'app-fake', template: ` <app-custom-tabs> <app-custom-tab> selected </app-custom-tab> </app-custom-tabs> ` }) class FakeComponent { }; fdescribe('CustomTabsComponent', () => { let component: FakeComponent; let fixture: ComponentFixture<FakeComponent>; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [FakeComponent, CustomTabsComponent, CustomTabComponent] }).compileComponents(); fixture = TestBed.createComponent(FakeComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); });
报错信息
Uncaught ReferenceError: Cannot access 'CustomTabComponent' before initialization
问题根源
这是循环引用引发的初始化顺序冲突:
- 父组件通过
@ContentChildren直接引用子组件类型 - 子组件构造器中又直接注入父组件类型
- 在Angular测试环境的初始化流程里,两个组件互相依赖,导致其中一个组件还未完成初始化就被另一个组件提前引用,触发报错。
解决办法
使用Angular提供的forwardRef延迟依赖解析,打破循环引用链:
修改子组件注入代码
import { forwardRef } from '@angular/core'; @Component({ selector: 'app-custom-tab', template: ` <div> <ng-content></ng-content> </div> ` }) export class CustomTabComponent { constructor(@Inject(forwardRef(() => CustomTabsComponent)) private _group: CustomTabsComponent) { } }
可选:同步修改父组件的@ContentChildren
若父组件的@ContentChildren仍存在初始化顺序问题,也可配合forwardRef调整:
import { forwardRef } from '@angular/core'; @Component({ selector: 'app-custom-tabs', template: ` <div class="inline-flex"> <ng-content select="app-custom-tab"></ng-content> </div> ` }) export class CustomTabsComponent { @ContentChildren(forwardRef(() => CustomTabComponent)) _tabs: QueryList<CustomTabComponent>; }
修改后,Angular会延迟对依赖组件的解析时机,确保两个组件都完成初始化后再建立引用关系,测试即可正常运行。
内容的提问来源于stack exchange,提问作者Carla C
相关产品推荐
相关产品推荐

