Angular自定义UndoSnackBar组件单元测试问题求助
Angular自定义Snackbar单元测试报错:找不到组件工厂
问题场景
已实现自定义UndoSnackbarComponent,并在TranslationSuggestionReviewModalComponent的showSnackbar方法中调用,但编写单元测试时触发组件工厂找不到的错误。
UndoSnackbarComponent.ts
import { Component } from '@angular/core'; import { MatSnackBarRef } from '@angular/material/snack-bar'; @Component({ selector: 'app-custom-snackbar', templateUrl: './undo-snackbar.component.html' }) export class UndoSnackbarComponent { message!: string; constructor(private snackBarRef: MatSnackBarRef<UndoSnackbarComponent>) {} onUndo(): void { this.snackBarRef.dismissWithAction(); } onDismiss(): void { this.snackBarRef.dismiss(); } }
TranslationSuggestionReviewModalComponent.ts(调用逻辑)
showSnackbar(): void { this.currentSnackbarRef = this.snackBar .openFromComponent<UndoSnackbarComponent>( UndoSnackbarComponent, { duration: COMMIT_TIMEOUT_DURATION, verticalPosition: 'bottom', horizontalPosition: 'right' }); this.currentSnackbarRef.instance.message = 'Suggestion queued'; this.currentSnackbarRef.onAction().subscribe(() => { this.undoReviewAction(); }); this.currentSnackbarRef.afterDismissed().subscribe(() => { if (this.hasQueuedSuggestion) { this.commitQueuedSuggestion(); } }); }
单元测试代码片段
class MockMatSnackBarRef { instance = { message: '' }; afterDismissed = () => of({ action: '', dismissedByAction: false }); onAction = () => of(undefined); } beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [ HttpClientTestingModule, OverlayModule, MatSnackBarModule ], declarations: [TranslationSuggestionReviewModalComponent], providers: [ NgbActiveModal, AlertsService, ContributionAndReviewService, LanguageUtilService, SiteAnalyticsService, ThreadDataBackendApiService, UserService, { provide: ChangeDetectorRef, useValue: changeDetectorRef }, MatSnackBar ], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); })); beforeEach(() => { snackBarSpy = spyOn(snackBar, 'openFromComponent').and.returnValue( new MockMatSnackBarRef() as unknown as MatSnackBarRef<unknown> ); });
报错信息
Chrome Headless 121.0.6167.160 (Mac OS 10.15.7)下测试失败,错误提示:
Error: No component factory found for UndoSnackbarComponent. Did you add it to @NgModule.entryComponents?
解决方法
1. 在测试模块中声明自定义Snackbar组件
Angular测试框架需要知晓所有被引用的组件,哪怕你用了NO_ERRORS_SCHEMA,如果测试逻辑触发了组件实例的创建流程,就必须在测试模块中声明该组件。修改TestBed.configureTestingModule的declarations数组:
declarations: [TranslationSuggestionReviewModalComponent, UndoSnackbarComponent],
如果UndoSnackbarComponent属于独立的功能模块,也可以直接导入该模块到测试模块的imports数组中。
2. 完善Mock对象的方法覆盖
当前的MockMatSnackBarRef缺少组件中调用的dismissWithAction和dismiss方法,补充后避免测试时调用真实方法抛出异常:
class MockMatSnackBarRef { instance = { message: '' }; afterDismissed = () => of({ action: '', dismissedByAction: false }); onAction = () => of(undefined); // 新增mock方法 dismissWithAction = jasmine.createSpy('dismissWithAction'); dismiss = jasmine.createSpy('dismiss'); }
3. 确保Spy绑定到正确的实例
确认snackBar实例是从TestBed注入的,避免出现多实例导致Spy失效:
let snackBar: MatSnackBar; let snackBarSpy: jasmine.Spy; beforeEach(() => { fixture = TestBed.createComponent(TranslationSuggestionReviewModalComponent); component = fixture.componentInstance; // 从测试床获取SnackBar实例 snackBar = TestBed.inject(MatSnackBar); snackBarSpy = spyOn(snackBar, 'openFromComponent').and.returnValue( new MockMatSnackBarRef() as unknown as MatSnackBarRef<UndoSnackbarComponent> ); fixture.detectChanges(); });
内容的提问来源于stack exchange,提问作者Ash2k3
相关产品推荐
相关产品推荐

