Angular: How to Mock Matdialogref While Testing
I Have a Dialogcomponent That Has the Following Constructor Where Dialog Is a Custom Object: Constructor( Public dialogRef: Matdialogref...
I have a DialogComponent that has the following constructor where Dialog is a custom object:
constructor(
public dialogRef: MatDialogRef<CustomDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: Dialog
)
I created the following TestBed in Angular4:
data = new Dialog()
data.message = 'Dialog Message'
TestBed.configureTestingModule({
imports: [MaterialModules],
declarations: [CustomDialogComponent],
providers: [MatDialogRef, { provide: Dialog, useValue: data }]
})
TestBed.overrideModule(BrowserDynamicTestingModule, {
set: {
entryComponents: [CustomDialogComponent]
}
})
await TestBed.compileComponents()
But I get the following error:
Failed: Can't resolve all parameters for MatDialogRef: (?, ?, ?).
Error: Can't resolve all parameters for MatDialogRef: (?, ?, ?).
changing providers to:
providers: [
{ provide: MatDialogRef, useValue: {} },
{ provide: MAT_DIALOG_DATA, useValue: data }
]
results in the following error:
Error: No provider for Dialog!
How do I resolve this?
5 Answers
I solved it by changing the component constructor to:
constructor(
public dialogRef: MatDialogRef<CustomDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: Dialog | any
)
The providers in the TestBed were:
providers: [{ provide: MatDialogRef, useValue: {} }, { provide: MAT_DIALOG_DATA, useValue: data }]
If you use at least one MatDialogRef method, you should create a mock.
For example I use the close() method. Without it errors would be generated so I made the below class with an empty method.
export class MatDialogRefMock {
close(value = '') {
}
}
and use that instead of an empty value, with useClass
{ provide: MatDialogRef, useClass: MatDialogRefMock },
Import MatDialogModule and MatDialogRef from angular/material/dialog instead of angular/material. Import the ModalDialogModule and provide providers for MatDialogRef in your TestBed.
Import {MatdialogModule,MatDialogRef} from '@angular/material/dialog';
TestBed.configureTestingModule({
declarations: [componentName],
imports: [MatdialogModule],
providers: [{provide : MatDialogRef, useValue : {}}]
});
To solve this problem, you can do the following steps:
1- You used the data as input to the dialog and used it in the constructor to set the variables. (in .ts)
constructor(public dialogRef: MatDialogRef<any>,
@Inject(MAT_DIALOG_DATA) public data: any) {
this.ip= data.ip;
this.name= data.name;
}
2- We should create fake data, (in .spec.ts)
const data = {
ip: '1.1.1.1',
name: 'test'
}
3- We define provider as follows And we introduce data, (in .spec.ts)
providers: [
{provide: MatDialogRef, useValue: {}},
{provide: MAT_DIALOG_DATA, useValue: data},
]
4- full code in .spec.ts
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {CustomDialogComponent} from './backup-list.component';
import {TranslateModule} from '@ngx-translate/core';
import {MAT_DIALOG_DATA, MatDialogModule, MatDialogRef} from '@angular/material';
import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/testing';
import {NO_ERRORS_SCHEMA} from '@angular/core';
const data = {
ip: '1.1.1.1',
name: 'test'
};
describe('BackupListComponent', () => {
let component: BackupListComponent;
let fixture: ComponentFixture<BackupListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [CustomDialogComponent],
imports: [
TranslateModule.forRoot(),
MatDialogModule,
BrowserDynamicTestingModule
],
providers: [
{provide: MatDialogRef, useValue: {}},
{provide: MAT_DIALOG_DATA, useValue: data},
],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
});
You can do this by the help of jasmine spy, as follow:
Step 1: Define the mock data
const data = {
title: 'title',
message: 'message',
summary: 'my summary'
};
Step 2: Create jasmine spy for MatDialogRef (Write this inside beforeEach block)
const matDialogSpy = jasmine.createSpyObj('MatDialogRef', ['onNoClick', 'closeDialog']);
onNoClick and closeDialog are methods inside MessagePopupComponnet
Step 3: Configure the TestBed as follow:
providers: [
{
provide: MatDialogRef,
useValue: matDialogSpy
},
{
provide: MAT_DIALOG_DATA,
useValue: data
}
]
For the ref, I've provided the full code below:
import { DebugElement } from "@angular/core";
import { async, ComponentFixture, TestBed } from "@angular/core/testing";
import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material";
import { MessagePopupComponent } from "./message-popup.component";
describe('MessagePopup', () => {
let fixture: ComponentFixture<MessagePopupComponent>;
let component: MessagePopupComponent;
let el: DebugElement;
let matDialogRef;
const data = {
title: 'title',
message: 'message',
summary: 'my summary'
};
beforeEach(async(() => {
const matDialogSpy = jasmine.createSpyObj('MatDialogRef', ['onNoClick', 'closeDialog']);
TestBed.configureTestingModule({
declarations: [MessagePopupComponent],
providers: [
{
provide: MatDialogRef,
useValue: matDialogSpy
},
{
provide: MAT_DIALOG_DATA,
useValue: data
}
]
}).compileComponents()
.then(() => {
fixture = TestBed.createComponent(MessagePopupComponent);
component = fixture.componentInstance;
el = fixture.debugElement;
matDialogRef = TestBed.get(MatDialogRef);
});
}));
fit('should create Message Popup component', () => {
expect(component).toBeTruthy('Message popup not created')
});
});