Angular: How to Mock Matdialogref While Testing

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<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?

2

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 }]
4

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 },
2

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 : {}}]
});
2

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')
  });

});
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Alexander Ross
Author

Alexander Ross

Alexander Ross has covered the video game industry for a decade, writing deep dives on game design, esports tournaments, VR developments, and gaming culture.