How can I test MatDialog.open in a constructor

50 Views Asked by At

I have a component that uses inside the constructor dialog open as so :

  dialog = inject( MatDialog );

  constructor () {

    this.dialog.open( WelcomeComponent , {
      width:'350px',
      height:'350px'
    } );

and I don't know how to test if open was called. The problem I'm facing is that the component is created before the jest.spyOn object which leads to 0 calls when trying:

  it( 'open welcome dialog', () => {
    const openDialogSpy = jest.spyOn( TestBed.inject(MatDialog), 'open' );
    expect( openDialogSpy ).toHaveBeenCalled();
    //I know this code leads to nothing but it's just an example
  }) 

EDIT:

Here is my test so far:

import { ElementRef } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { AppComponent } from './app.component';
import { MediaService } from './services/media.service';
import { WelcomeComponent } from './welcome/welcome.component';

describe('AppComponent', () => {

  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports:[AppComponent, NoopAnimationsModule, MatDialogModule ],
      providers:[
        { provide:ElementRef, useValue:{}},
        { provide:MediaService, useValue:{}},
        { provide:MatDialog },
      ]
    }).compileComponents();
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it( 'open welcome dialog', () => {

    const dialogSpy = jest.spyOn(component.dialog, 'open')
    component.dialog.open( WelcomeComponent , {
      width:'350px',
      height:'350px'
    } );
    expect( dialogSpy ).toHaveBeenCalledTimes(1);

  })

});
2

There are 2 best solutions below

1
Naren Murali On BEST ANSWER

Could you try reinitializing the createComponent once you attach the jest spyOn

it( 'open welcome dialog', () => {
    const dialogSpy = jest.spyOn(component.dialog, 'open')
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
    expect( dialogSpy ).toHaveBeenCalledTimes(1);

})
1
Helmi On
  • You should provide the MatDialog service using useClass instead of just declaring it in the providers array.
  • The MatDialog module should be imported in the imports array, not in the TestBed.configureTestingModule object.
  • You should use TestBed.inject(MatDialog) to get the instance of MatDialog in your test.

i hope this solve your problem

import { ElementRef } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { AppComponent } from './app.component';
import { MediaService } from './services/media.service';
import { WelcomeComponent } from './welcome/welcome.component';

describe('AppComponent', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [NoopAnimationsModule, MatDialogModule],
      declarations: [AppComponent], // Declare the component being tested
      providers: [
        { provide: ElementRef, useValue: {} },
        { provide: MediaService, useValue: {} },
        MatDialog // Provide MatDialog using useClass
      ]
    }).compileComponents();
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should open welcome dialog', () => {
    const dialog = TestBed.inject(MatDialog); // Get MatDialog instance using TestBed.inject
    const dialogSpy = jest.spyOn(dialog, 'open');

    component.openWelcomeDialog();

    expect(dialogSpy).toHaveBeenCalledTimes(1);
    expect(dialogSpy).toHaveBeenCalledWith(WelcomeComponent, {
      width: '350px',
      height: '350px'
    });
  });
});

My suggestion is to create a separate function to open the dialog and place it in either ngOnInit or ngAfterViewInit.

  constructor () {
       openDialog()
    }

 openDialog(){
    this.dialog.open( WelcomeComponent , {
      width:'350px',
      height:'350px'
    } );
 }