Angular对话框单元测试报错:this.dialogRef.close不是函数求解决方案
解决Angular对话框单元测试中
dialogRef.close is not a function错误 我帮你排查了下代码,问题主要出在MatDialogRef的Mock配置错误和测试中未正确跟踪close方法调用这两个地方,下面一步步给你讲怎么修复:
1. 修正MatDialogRef的Provider配置
你在TestBed里配置MatDialogRef的时候犯了个小错误:
{provide: MatDialogRef, useValue: {dialogMock}},
这里你把dialogMock包在了一个额外的对象里,导致组件注入的dialogRef其实是{dialogMock: {close: ...}}这样的结构,自然找不到直接挂载的close方法。直接把dialogMock作为useValue的值就行:
{provide: MatDialogRef, useValue: dialogMock},
2. 正确设置Spy来跟踪close方法调用
你当前的测试直接断言component.dialogRef.close被调用,但没有给这个方法设置Spy监听。需要提前给Mock的close方法创建Spy,这样才能准确跟踪它的调用情况。另外,Angular新版本里更推荐用waitForAsync替代旧的async语法,我也帮你同步调整了。
修改后的完整测试代码
import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing'; import {CloneDialogComponent} from "./cloneDialog.component"; import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from '@angular/material/dialog'; import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; describe('CloneDialogComponent', () => { let component: CloneDialogComponent; let fixture: ComponentFixture<CloneDialogComponent>; // 直接在mock里创建close方法的spy,方便后续断言 const dialogMock = { close: jasmine.createSpy('close') }; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ declarations: [ CloneDialogComponent ], imports: [ MatDialogModule, BrowserAnimationsModule ], providers: [ // 移除了不必要的MatDialogTitle依赖,组件里没用到它 {provide: MatDialogRef, useValue: dialogMock}, {provide: MAT_DIALOG_DATA, useValue: []} ] }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(CloneDialogComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should be created', () => { expect(component).toBeTruthy(); }); it('should call onNoClick when No button is clicked', waitForAsync(() => { spyOn(component, 'onNoClick'); const button = fixture.debugElement.nativeElement.querySelector('#no'); button.click(); fixture.whenStable().then(() => { expect(component.onNoClick).toHaveBeenCalled(); }); })); it('should call onYesClick when Yes button is clicked', waitForAsync(() => { spyOn(component, 'onYesClick'); const button = fixture.debugElement.nativeElement.querySelector('#yes'); button.click(); fixture.whenStable().then(() => { expect(component.onYesClick).toHaveBeenCalled(); }); })); it('should close dialog with false after onNoClick', () => { component.onNoClick(); expect(dialogMock.close).toHaveBeenCalledWith(false); }); it('should close dialog with true after onYesClick', () => { component.onYesClick(); expect(dialogMock.close).toHaveBeenCalledWith(true); }); });
额外说明
- 我把
async换成了Angular官方推荐的waitForAsync,同时在按钮点击测试里加了fixture.whenStable()来确保异步操作完成后再断言; - 直接在
dialogMock里用jasmine.createSpy创建了close方法的Spy,不仅能断言是否被调用,还能验证调用时传入的参数是否正确; - 移除了不必要的
MatDialogTitleProvider,你的组件里并没有注入这个依赖,完全不需要额外提供。
按照上面的修改,你应该就能解决dialogRef.close is not a function的错误,同时正确测试对话框的关闭逻辑了。
内容的提问来源于stack exchange,提问作者juju
相关产品推荐
相关产品推荐

