I am new to angular development and more new towards unit testing using jasmine. I have created a component to sow a dialog using angular material MatDialogRef, MAT_DIALOG_DATA from @angular/material. The component is working fine but the Unit testing is giving me an error which i am not able to resolve.
I really need this to work and any help would be appreciated.... Thanks in advance..!!!
Please find my code below:
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { HttpModule } from '@angular/http';
import { RouterModule, Routes } from '@angular/router';
import 'hammerjs';
import { NgxPhoneSelectModule } from 'ngx-phone-select';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatInputModule, MatButtonModule, MatSelectModule } from '@angular/material';
import { MatGridListModule } from '@angular/material';
import { MatTableModule } from '@angular/material';
import { MatDialogModule} from '@angular/material';
import { MatCardModule} from '@angular/material';
import { MaterialModule } from './modules/material/material.module';
import { AppComponent } from './app.component';
import { CustomerComponent } from './components/customer/customer.component';
import { LoginComponent } from './components/login/login.component';
import { ForgetPasswordComponent } from './components/forget-password/forget-password.component';
import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
import { DashboardComponent } from './components/dashboard/dashboard.component';
import { LoaderService } from './services/loader.service';
import { CustomerDataService } from './services/customer-data.service';
import { UserService } from './services/user/user.service';
import { HeaderComponent } from './components/header/header.component';
import { UpdateCustomerComponent } from './components/update-customer/update-customer.component';
import { AuthService } from './services/auth.service';
import { AuthGuard } from './services/auth/auth.guard';
import { DeleteCustomerComponent } from './components/delete-customer/delete-customer.component';
import { FooterComponent } from './components/footer/footer.component';
const appRoutes: Routes = [
{
path: '',
component: LoginComponent
},
{
path: 'create-customer',
component: CustomerComponent,
// canActivate: [AuthGuard] // ristrict direct access of links
},
{
path: 'forget-password',
component: ForgetPasswordComponent,
// canActivate: [AuthGuard] // ristrict direct access of links
},
{
path: 'dashboard',
component: DashboardComponent,
// canActivate: [AuthGuard] // ristrict direct access of links
},
{
path: 'update-customer',
component: UpdateCustomerComponent,
// canActivate: [AuthGuard] // ristrict direct access of links
},
{
path: '**',
component: PageNotFoundComponent
}
];
@NgModule({
declarations: [
AppComponent,
CustomerComponent,
LoginComponent,
ForgetPasswordComponent,
PageNotFoundComponent,
DashboardComponent,
HeaderComponent,
UpdateCustomerComponent,
DeleteCustomerComponent,
FooterComponent
],
imports: [
BrowserModule,
HttpClientModule,
HttpModule,
RouterModule.forRoot(appRoutes),
NgxPhoneSelectModule,
BrowserAnimationsModule,
FormsModule,
ReactiveFormsModule,
MatInputModule,
MatButtonModule,
MatSelectModule,
MatGridListModule,
MatTableModule,
MaterialModule
],
entryComponents: [
DeleteCustomerComponent
],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
providers: [LoaderService, AuthService, AuthGuard, UserService, CustomerDataService],
bootstrap: [AppComponent]
})
export class AppModule { }
delete customer component
import { Component, OnInit, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { Router} from '@angular/router';
@Component({
selector: 'app-delete-customer',
templateUrl: './delete-customer.component.html',
styleUrls: ['./delete-customer.component.scss']
})
export class DeleteCustomerComponent implements OnInit {
constructor(private router: Router, public deleteCustDialogRef: MatDialogRef<DeleteCustomerComponent>, @Inject(MAT_DIALOG_DATA) public data: string) { }
ngOnInit() {
}
onClosedeleteCustomer() {
this.deleteCustDialogRef.close('confirm');
this.router.navigate(['./dashboard']);
}
onCloseCancel() {
this.deleteCustDialogRef.close('cancel');
}
}
delete-customer.component.spec.ts
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import {RouterTestingModule} from '@angular/router/testing';
import { DeleteCustomerComponent } from './delete-customer.component';
import { MaterialModule } from '../../modules/material/material.module';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialog, MatDialogModule } from '@angular/material';
describe('DeleteCustomerComponent', () => {
let component: DeleteCustomerComponent;
let fixture: ComponentFixture<DeleteCustomerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ DeleteCustomerComponent ],
imports: [ MaterialModule, RouterTestingModule, MatDialogModule ],
providers : [ MatDialogRef, MAT_DIALOG_DATA, MatDialog ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DeleteCustomerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
karma error
DeleteCustomerComponent should create
Failed: Can't resolve all parameters for MatDialogRef: (?, ?, ?).
Error: Can't resolve all parameters for MatDialogRef: (?, ?, ?).
at syntaxError (http://localhost:9876/_karma_webpack_/webpack:/C:/dewatering_FST/node_modules/@angular/compiler/esm5/compiler.js:485:22)
at CompileMetadataResolver.webpackJsonp.../../../compiler/esm5/compiler.js.CompileMetadataResolver._getDependenciesMetadata (http://localhost:9876/_karma_webpack_/webpack:/C:/dewatering_FST/node_modules/@angular/compiler/esm5/compiler.js:15662:1)
at CompileMetadataResolver.webpackJsonp.../../../compiler/esm5/compiler.js.CompileMetadataResolver._getTypeMetadata (http://localhost:9876/_karma_webpack_/webpack:/C:/dewatering_FST/node_modules/@angular/compiler/esm5/compiler.js:15497:1)
at CompileMetadataResolver.webpackJsonp.../../../compiler/esm5/compiler.js.CompileMetadataResolver._getInjectableMetadata (http://localhost:9876/_karma_webpack_/webpack:/C:/dewatering_FST/node_modules/@angular/compiler/esm5/compiler.js:15477:1)
at CompileMetadataResolver.webpackJsonp.../../../compiler/esm5/compiler.js.CompileMetadataResolver.getProviderMetadata (http://localhost:9876/_karma_webpack_/webpack:/C:/dewatering_FST/node_modules/@angular/compiler/esm5/compiler.js:15837:1)
at http://localhost:9876/_karma_webpack_/webpack:/C:/dewatering_FST/node_modules/@angular/compiler/esm5/compiler.js:15748:1
at Array.forEach (<anonymous>)
at CompileMetadataResolver.webpackJsonp.../../../compiler/esm5/compiler.js.CompileMetadataResolver._getProvidersMetadata (http://localhost:9876/_karma_webpack_/webpack:/C:/dewatering_FST/node_modules/@angular/compiler/esm5/compiler.js:15708:1)
at CompileMetadataResolver.webpackJsonp.../../../compiler/esm5/compiler.js.CompileMetadataResolver.getNgModuleMetadata (http://localhost:9876/_karma_webpack_/webpack:/C:/dewatering_FST/node_modules/@angular/compiler/esm5/compiler.js:15276:1)
at JitCompiler.webpackJsonp.../../../compiler/esm5/compiler.js.JitCompiler._loadModules (http://localhost:9876/_karma_webpack_/webpack:/C:/dewatering_FST/node_modules/@angular/compiler/esm5/compiler
Depending on your needs, a more simple approach is injecting a mock MatDialog provider that has a jasmine spy for the close or open methods. For instance:
import { MyDialogComponent } from './mydialog.component';
import { async, TestBed, inject } from '@angular/core/testing';
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
import { MatDialog } from '@angular/material/dialog';
describe('MyDialogComponent', () => {
const mockDialogRef = {
close: jasmine.createSpy('close')
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [MyDialogComponent],
imports: [MatDialogModule],
providers: [
{
provide: MatDialogRef,
useValue: mockDialogRef
}
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MyDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('#onClosedeleteCustomer should close the dialog', () => {
component.onClosedeleteCustomer();
expect(mockDialogRef.close).toHaveBeenCalled();
});
});
This gist is, don't inject the real instance of the MatDialog or MatDialogRef in your test. Inject a mock object instead with a jasmine spy that can tell you if a method has been called.
When I was trying to test the dialog component I encountered the same issue. My solution is based on the dialog test in angular-material source code.
import { MyDialogComponent } from './mydialog.component';
import { async, TestBed, inject } from '@angular/core/testing';
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { MatDialog } from '@angular/material/dialog';
import { OverlayContainer } from '@angular/cdk/overlay';
describe('MyDialogComponent', () => {
let dialog: MatDialog;
let overlayContainer: OverlayContainer;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [MyDialogComponent],
imports: [
MatDialogModule,
]
});
TestBed.overrideModule(BrowserDynamicTestingModule, {
set: {
entryComponents: [MyDialogComponent]
}
});
TestBed.compileComponents();
}));
beforeEach(inject([MatDialog, OverlayContainer],
(d: MatDialog, oc: OverlayContainer) => {
dialog = d;
overlayContainer = oc;
})
);
afterEach(() => {
overlayContainer.ngOnDestroy();
});
it('should open a dialog with a component', () => {
const dialogRef = dialog.open(MyDialogComponent, {
data: { param: '1' }
});
// verify
expect(dialogRef.componentInstance instanceof MyDialogComponent).toBe(true);
});
});
I'm not sure this is the right approach though, still a beginner myself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With