angular - 在 Jasmine 中对 MatDialog 进行单元测试时无法读取未定义的属性 'afterClosed'

标签 angular typescript dialog jasmine angular-material

我从 Karma Jasmine 收到以下错误:
TypeError:无法读取未定义的属性“afterClosed”

我认真搜索过,但在 Stack Overflow 或其他来源中找不到解决方案。

这就是我在组件中打开 MatDialog 的方式:
(喜欢documented)

constructor(public dialog: MatDialog) {}

public openDialog(): void {
    const dialogReference: MatDialogRef<any, any> = this.dialog.open(myDialogComponent, {
        width: '1728px'
    });

    dialogReference.afterClosed().subscribe((result) => {
    });
}

这是我的单元测试配置:

beforeEach(async(() => {
    TestBed.configureTestingModule({
        declarations: [
            myRequestComponent
        ],
        imports: [
            MatDialogModule,
            ReactiveFormsModule
        ],
        providers: [
            { provide: MatDialog, useValue: {} },
        ],
        schemas: [CUSTOM_ELEMENTS_SCHEMA]
    }).compileComponents();
}));

beforeEach(() => {
    fixture = TestBed.createComponent(myRequestComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
});

这是我的单元测试:

it('openDialog() should open a dialog', () => {
    spyOn(component.dialog, 'open');

    component.openDialog();

    expect(component.dialog.open).toHaveBeenCalled();
});

我是否必须模拟 MatDialog 或 MatDialogReference?

最佳答案

让我们逐步解决您的问题。

首先,通过注册

providers: [{ provide: MatDialog, useValue: {} }],

每当 MatDialog 需要解析时,您的测试台将注入(inject)一个没有行为的对象(例如实例方法/成员)。

这并不是真正必要的,因为您正在将 MatDialogModule 导入到您的测试台中,因此可以毫无问题地解决 MatDialog 的实例。 但让我们坚持您的方法。此解决方案将要求您删除该行。

其次,通过做:

spyOn(component.dialog, 'open')

您正在为 component.dialog 引用的对象中的 open 实例方法安装一个代理。在这种情况下,您之前注册的空对象。

尽管对象没有这样的成员,jasmine 会动态地在它的位置添加代理。这就是为什么您没有看到类似 this.dialog.open is not a function 的错误。

最后,无论何时与之交互,代理都会记录有关这些交互的信息并将调用重定向到原始的open 成员。因为没有原始实现,a function with no return will be used in its place ,这将最终触发 accessing foo of undefined

TL;DR;

删除 { provide: MatDialog, useValue: {} } 并使用以下命令模拟所需的 MatDialogRef 实例:

import { EMPTY} from 'rxjs';

it('openDialog() should open a dialog', () => {
    const openDialogSpy = spyOn(component.dialog, 'open')
        .and
        .returnValue({afterClosed: () => EMPTY});

    component.openDialog();

    expect(openDialogSpy).toHaveBeenCalled();
});

关于angular - 在 Jasmine 中对 MatDialog 进行单元测试时无法读取未定义的属性 'afterClosed',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54767811/

相关文章:

android - Google登录对话框关闭android studio后屏幕闪烁

css - Normalize.css 不起作用 Angular 4/5

javascript - 无法获取订阅函数内组件的 'this'

javascript - @typescript-eslint/eslint-插件错误 : 'Route' is defined but never used (no-unused-vars)

typescript - 如何找到最新的 Typings 定义?

java - 空指针错误?

android - 当前时间选择器

具有嵌套状态的 Angular2 路由

angular - 在 Angular 中根据路由动态添加元描述

angular - 我们可以在 angular 7 的 index.html 中添加 <div id ="api"></div> 吗?