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

Angular11-12基于Jasmine测试MatDialog的afterClosed订阅报错咨询

问题根源与修复方案

核心报错原因

你遇到的TypeError: Cannot read property 'close' of undefined和afterClosed不触发的问题,主要是4个问题叠加导致的:

  • 测试中spy时机错误:你在点击按钮触发modificar方法前,就spy了初始化时注入的dialogRef实例,但modificar方法执行时会将this.dialogRef重写为dialog.open()的返回值,你提前spy的旧实例根本不会被用到
  • MatDialogMock的open方法返回值不符合预期:你当前mock的open方法返回的是一个只有afterClosed的临时对象,没有close方法,也不是你定义的MatDialogRefMock实例,赋值给dialogRef后调用close自然报错
  • spydialog.open时没有加callThrough:默认spy会替换原方法实现,你mock的open方法根本不会执行,导致dialogRef一直是初始化注入的旧值,甚至没被重新赋值
  • 组件代码变量名写错:afterClosed的回调参数是resultados,但你判断的是未定义的resul,就算订阅触发也走不到服务调用的逻辑里

分步修改

1. 修复组件代码变量名问题

this.dialogRef.afterClosed().subscribe(
    // 把回调参数名和判断变量统一
    resultados => {
        if(resultados){ // 原来的resul是未定义变量,改为resultados
            this.service.realiza(resultados).subscribe(
                // 原有逻辑不变
            )
        }
    }
);

额外说明:你的组件是打开对话框的父组件,不需要在构造函数里注入MatDialogRef,这部分属于冗余代码可以删掉,只有对话框本身才需要注入MatDialogRef。

2. 修正MatDialogMock的实现

让open方法返回MatDialogRefMock实例,保证有close方法:

export class MatDialogMock {
    open() {
        // 返回你定义的MatDialogRefMock实例,而不是临时对象
        return new MatDialogRefMock();
    }
}

如果需要自定义关闭返回值,可以给MatDialogRefMock加属性控制:

export class MatDialogRefMock {
    // 自定义关闭返回值
    closeResult:any = {
        group: {
            id: "1CESO",
            refFrame: "B"
        }
    };
    close():void{}
    afterClosed(): Observable<any>{
        return of(this.closeResult);
    }
}

3. 修正测试用例逻辑

it('点击按钮打开对话框,关闭后调用服务提交修改', ()=>{
    const spy1 = spyOn(component, 'modificar').and.callThrough();
    // spy dialog.open时要加callThrough,才会执行你mock的open方法
    const spy2 = spyOn(component["dialog"], 'open').and.callThrough();

    const service = fixture.debugElement.injector.get(CustomService);
    const spy4 =spyOn(service, 'realiza').and.callThrough();

    fixture.detectChanges();
    // 点击按钮触发modificar方法
    const botonEditar= fixture.debugElement.query(By.css('#but'));
    botonEditar.nativeElement.click();
    fixture.detectChanges();

    // 此时dialogRef已经被赋值为open返回的MatDialogRefMock实例,不需要手动调用close
    // 因为afterClosed返回的是of(),是立即发射值的冷observable,订阅后已经触发回调逻辑

    expect(spy1).toHaveBeenCalled();
    expect(spy2).toHaveBeenCalled();
    // 验证服务被调用,且参数正确
    expect(spy4).toHaveBeenCalledOnceWith({
        group: {
            id: "1CESO",
            refFrame: "B"
        }
    });
});

额外说明

不需要手动调用component["dialogRef"].close(),因为你的mock里afterClosed直接返回of(...),只要订阅就会立即执行回调逻辑,完全模拟了对话框关闭返回结果的行为。

内容的提问来源于stack exchange,提问作者DavidB

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 23:51:03