You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

测试@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


问题根源

这是循环引用引发的初始化顺序冲突:

  1. 父组件通过@ContentChildren直接引用子组件类型
  2. 子组件构造器中又直接注入父组件类型
  3. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 05:40:02