gpt4 book ai didi

Angular Jest 测试打开 MatDialog 的组件 - 打开不是函数

转载 作者:行者123 更新时间:2023-12-04 02:34:18 24 4
gpt4 key购买 nike

类似于 this问题,但它没有提供适合我的答案。

我有一个简单的组件,它有一个打开对话框的方法:

  enterGiveaway() {
this.dialog.open(SpendTicketsDialogComponent, {
width: '370px',
height: '600px'
});
}

现在我只想测试调用该方法会导致对话框打开。

测试失败并出现以下错误:

  expect(spy).toBeCalledTimes(expected)

Expected number of calls: 1
Received number of calls: 0

使用此代码:

    import {async, ComponentFixture, TestBed} from '@angular/core/testing';

import {GiveawayItemComponent} from './giveaway-item.component';
import {giveawaysMock} from '../../../../../mocks/giveaways.mock';
import {MaterialModule} from '../../material.module';
import {getTranslocoModule} from '../../../transloco-testing.module';
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {MatDialog} from '@angular/material/dialog';
import {EMPTY} from 'rxjs';
import {SpendTicketsDialogComponent} from '../dialogs/tickets-dialog/spend-tickets-dialog.component';
import {NumberFormatter} from '../../filters/numberFormatter/numberFormatter.filter';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {BrowserModule} from '@angular/platform-browser';

describe('GiveawayItemComponent', () => {
let component: GiveawayItemComponent;
let fixture: ComponentFixture<GiveawayItemComponent>;
let dialog: any;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
GiveawayItemComponent,
SpendTicketsDialogComponent,
NumberFormatter
],
imports: [
MaterialModule,
BrowserAnimationsModule,
getTranslocoModule({})
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.overrideModule(BrowserModule, {
set: {entryComponents: [SpendTicketsDialogComponent]}
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(GiveawayItemComponent);
component = fixture.componentInstance;
component.giveaway = giveawaysMock[0];
component.numberOfChances = 100;
dialog = TestBed.inject(MatDialog);
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

describe('enterGiveaway', () => {
it('should open the spend tickets dialog', async(() => {
component.enterGiveaway();
fixture.detectChanges();
const spy = spyOn(dialog, 'open').and.returnValue({
afterClosed: () => EMPTY
});

expect(spy).toBeCalledTimes(1);
}));
});
});

我当然明白,MatDialog 没有引用实际打开的 SpendTicketsDialogComponent。所以我尝试为对话框提供一个模拟对象:

    import {async, ComponentFixture, TestBed} from '@angular/core/testing';

import {GiveawayItemComponent} from './giveaway-item.component';
import {giveawaysMock} from '../../../../../mocks/giveaways.mock';
import {MaterialModule} from '../../material.module';
import {getTranslocoModule} from '../../../transloco-testing.module';
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {MatDialog} from '@angular/material/dialog';
import {of} from 'rxjs';
import {SpendTicketsDialogComponent} from '../dialogs/tickets-dialog/spend-tickets-dialog.component';
import {NumberFormatter} from '../../filters/numberFormatter/numberFormatter.filter';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {BrowserModule} from '@angular/platform-browser';

class dialogMock {
open() {
return {
afterClosed: () => of({})
};
}
}

describe('GiveawayItemComponent', () => {
let component: GiveawayItemComponent;
let fixture: ComponentFixture<GiveawayItemComponent>;
let dialog: any;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
GiveawayItemComponent,
SpendTicketsDialogComponent,
NumberFormatter
],
imports: [
MaterialModule,
BrowserAnimationsModule,
getTranslocoModule({})
],
providers: [{provide: MatDialog, useValue: dialogMock}],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.overrideModule(BrowserModule, {
set: {entryComponents: [SpendTicketsDialogComponent]}
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(GiveawayItemComponent);
component = fixture.componentInstance;
component.giveaway = giveawaysMock[0];
component.numberOfChances = 100;
dialog = TestBed.inject(MatDialog);
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

describe('enterGiveaway', () => {
it('should open the spend tickets dialog', async(() => {
component.enterGiveaway();
fixture.detectChanges();
const spy = spyOn(dialog, 'open').and.callThrough();

expect(spy).toBeCalledTimes(1);
}));
});
});

但这会引发错误this.dialog.open is not a function

我实际上认为这两种解决方案都不正确,因为我需要检查调用 enterGiveaway 是否打开了 SpendTicketsDialog。

那么我该如何验证呢?

最佳答案

您对 MatDialog 的模拟还不够好。

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

由于 dialogMock 是一个类,那么您应该像这样使用它:

useValue: new dialogMock()

useClass: dialogMock

否则你的模拟将没有 open 方法。

Tip: always name your classes with Capital letter

现在让我们转到您的测试用例并注意执行顺序:

component.enterGiveaway();   <-------------------------  (1)         
...
const spy = spyOn(dialog, 'open').and.callThrough(); <-- (2)

expect(spy).toBeCalledTimes(1); <----------------------- (3)
  • (1) 是执行 modal.open() 方法的地方。如果我们为对话框提供了更正的模拟,那么它将毫无问题地执行

  • (2) 是您监视对话方法以计算调用次数的地方。 以后不会调用此 spy 。 modal.open() 已经在步骤 (1)

    执行
  • (3) 您的测试失败,因为由于 (2) 步骤中所述的原因,没有对您的 spy 进行任何调用。

解决方案非常不言自明:在执行 enterGiveaway() 方法之前放置 spy 程序:

  const spy = spyOn(dialog, 'open').and.callThrough();
component.enterGiveaway();

jasmine.createSpyObj

还有另一种方便的方法可以使用 jasmine.createSpyObj 模拟您的 MatDialogopen 方法。

let dialog: jasmine.SpyObj<MatDialog>;
...

{provide: MatDialog, useValue: jasmine.createSpyObj<MatDialog>(['open'])}

beforeEach(() => {
...
dialog = TestBed.inject(MatDialog) as jasmine.SpyObj<MatDialog>;
...
});

it('should open the spend tickets dialog', async(() => {
component.enterGiveaway();

expect(dialog.open.calls.count()).toBe(1);
}));

关于Angular Jest 测试打开 MatDialog 的组件 - 打开不是函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62558674/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com