Learn Angular : Testing Component With Material Dialog | MatDialog | Karma | Jasmine


You already saw how to use Material MatDialog in Angular. In this tutorial, you’ll learn how to unit test components having Material MatDialog.

Source code from this tutorial is available at GitHub.

You can also follow the video tutorial on YouTube. {% include youtube_embed.html id=“m3BY6333CKc” %}

Running Angular Unit Tests

For the sake of this tutorial , you’ll clone the source code from the Angular Material MatDialog tutorial.

git clone https://github.com/jay3dec/upgraded-winner
cd upgraded-winner
npm install
npm start

You’ll have the Angular application running.

Stop the Angular application server. From the project directory, using the Angular CLI command, let’s run the default unit test cases.

ng test --code-coverage

--code-coverage options let’s you see the code coverage.

Once the unit test cases are executed, it will show the following results.

TOTAL: 4 FAILED, 0 SUCCESS
TOTAL: 4 FAILED, 0 SUCCESS
TOTAL: 4 FAILED, 0 SUCCESS

Adding MatDialog Dependencies

You will getting the following dependency error related to MatDialog, NullInjectorError: No provider for MatDialog!

You have two components in the Angular application, AppComponent and PopUpComponent. Since AppComponent is using the MatDialog let’s add the dependency to app.component.spec.ts file.

Import MatDialogModule to the app.component.spec.ts and also remove the last unit test case, since it’s irrelevant to our code.

import { TestBed, async } from '@angular/core/testing';
import { MatDialogModule } from '@angular/material/dialog';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';

describe('AppComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule,
        MatDialogModule
      ],
      declarations: [
        AppComponent
      ],
    }).compileComponents();
  }));

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app).toBeTruthy();
  });

  it(`should have as title 'angular-mateiral'`, () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app.title).toEqual('angular-mateiral');
  });
});

Now there is one more dependency failure related to MatDialogData in PopupComponent.

NullInjectorError: No provider for InjectionToken MatDialogData!

Let’s add a provider for the same in pop-up.component.spec.ts file.

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

Here is how the complete pop-up.component.spec.ts file looks :

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { PopUpComponent } from './pop-up.component';

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ PopUpComponent ],
      providers : [{
        provide : MAT_DIALOG_DATA,
        useValue : {}
      }]
    })
    .compileComponents();
  }));

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

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

Save the above changes and the unit test cases should run fine without any dependency errors.

Unit Testing Component With MatDialog

Let’s add a new unit test case for testing the openDialog method which utilizes the MatDialog instance to show the modal popup.

In app.component.spec.ts file let’s add a new unit test case as shown:

  it('should call openDialog', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    app.openDialog();
  })

Using the app instance you are triggering the openDialog method. Now the app HTML should have the popup HTML. So, let’s try to get the popup HTML and check it to have the expected header title.

  it('should call openDialog', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    const expected_header = "Welcome Samuel";
    app.openDialog();
    fixture.detectChanges();
    const popUpHeader = document.getElementsByTagName('h2')[0] as HTMLHeadElement;
    expect(popUpHeader.innerText).toEqual(expected_header);
  })

As seen in the above code, fixture.detectChanges helps to detect the changes once the openDialog method has been called.

Save the above changes and run the unit test cases and you will be able to that it passes successfully.

Chrome 90.0.4430.85 (Windows 10): Executed 4 of 4 SUCCESS (0.082 secs / 0.071 secs)
TOTAL: 4 SUCCESS
TOTAL: 4 SUCCESS
TOTAL: 4 SUCCESS

=============================== Coverage summary ===============================
Statements   : 100% ( 12/12 )
Branches     : 100% ( 0/0 )
Functions    : 100% ( 4/4 )
Lines        : 100% ( 10/10 )
================================================================================

Wrapping it up

In this tutorial, you learnt how to write unit test cases for Angular components with MatDialog. You also learnt how to resolve the following dependency issues, NullInjectorError: No provider for MatDialog! NullInjectorError: No provider for InjectionToken MatDialogData! while running MatDialog containing unit test cases.

Source code from this tutorial is available at GitHub.