Angular独立指令单元测试中输入绑定失败问题排查
问题:Angular Signal Inputs在Jest单元测试中绑定失败
在为Angular CDK Table的自定义指令编写单元测试时,调用fixture.detectChanges()后抛出两个错误:
Can't bind to 'sortableColumns' since it isn't a known property of 'table' (used in the 'TestComponent' component template)ERROR RuntimeError: NG0950: Input is required but no value is available yet.
测试组件代码
@Component({ standalone: true, imports: [CdkTableModule, SortableTableDirective], template: ` <table cdk-table sortableTable [dataSource]="dataSource" [sortableColumns]="sortableColumns"> <ng-container cdkColumnDef="columnA"> <th cdk-header-cell *cdkHeaderCellDef>The First Column</th> <td cdk-cell *cdkCellDef="let element">{{ element.columnA }}</td> </ng-container> <ng-container cdkColumnDef="columnB"> <th cdk-header-cell *cdkHeaderCellDef>The Second Column</th> <td cdk-cell *cdkCellDef="let element">{{ element.columnB }}</td> </ng-container> <ng-container cdkColumnDef="columnC"> <th cdk-header-cell *cdkHeaderCellDef>The Third Column</th> <td cdk-cell *cdkCellDef="let element">{{ element.columnC }}</td> </ng-container> <tr cdk-header-row *cdkHeaderRowDef="displayedColumns"></tr> <tr cdk-row *cdkRowDef="let row; columns: displayedColumns"></tr> </table>`, }) class TestComponent { dataSource = // 数据源创建逻辑已简化 sortableColumns = ['columnA', 'columnB']; displayedColumns = ['columnA', 'columnB', 'columnC']; }
测试初始化代码
beforeEach(async () => { await TestBed.configureTestingModule({ imports: [SortableTableDirective, TestComponent, CdkTableModule], }).compileComponents(); fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); table = fixture.debugElement.query(By.directive(SortableTableDirective)); });
自定义指令代码
@Directive({ selector: 'table[sortableTable]', standalone: true, }) export class SortableTableDirective<T> implements OnDestroy { dataSource = input.required<SortableDatasource<T>>(); sortableColumns = input.required<string[]>(); public constructor( private renderer: Renderer2, private elRef: ElementRef, private containerRef: ViewContainerRef, ) { // 逻辑已简化 } }
补充信息
- 生产环境代码运行正常,CDK Table元素可在fixture中正常获取;
- 将signal inputs替换为传统
@Input()装饰器后,绑定问题消失; - 最小复现项目在Karma+Jasmine环境下无此问题,仅Jest环境出现错误。
可能的原因与解决方案
原因
问题根源在于Jest测试工具链对Angular Signal Inputs的兼容性不足,尤其是较旧版本的@angular-builders/jest或jest-preset-angular,未能正确识别signal inputs对应的绑定属性。
解决方案
- 升级测试依赖:更新
@angular-builders/jest、jest-preset-angular到最新版本,新版本通常会修复signal inputs的测试支持问题。 - 调整detectChanges调用时机:确保组件属性初始化完成后再调用
fixture.detectChanges(),避免signal inputs在未获取值时被检测:beforeEach(async () => { await TestBed.configureTestingModule({ imports: [SortableTableDirective, TestComponent, CdkTableModule], }).compileComponents(); fixture = TestBed.createComponent(TestComponent); // 确保数据源等属性初始化完成 fixture.componentInstance.dataSource = /* 完整的数据源实例 */; fixture.detectChanges(); table = fixture.debugElement.query(By.directive(SortableTableDirective)); }); - 临时回退到@Input():如果升级依赖无法解决,可暂时将signal inputs替换为带
required: true的@Input(),待Jest工具链完善后再切换回signal inputs:@Directive({ selector: 'table[sortableTable]', standalone: true, }) export class SortableTableDirective<T> implements OnDestroy { @Input({ required: true }) dataSource!: SortableDatasource<T>; @Input({ required: true }) sortableColumns!: string[]; // 其余逻辑保持不变 }
内容的提问来源于stack exchange,提问作者JoBos
相关产品推荐
相关产品推荐

