Reputation: 15321
I have a strange error with my unit tests and for some reason I cannot determine why I am getting this error. U have only two tests. One to make sure the component is created and the other to check that when a component method is called it calls the Mat Dialog .open method... nothing too complex. Here is my code...
describe('ClientDeactivateComponent', () => {
let component: ClientDeactivateComponent;
let fixture: ComponentFixture<ClientDeactivateComponent>;
const spyMatDialog = jasmine.createSpyObj('MatDialog', ['open']);
const spyRouter = jasmine.createSpyObj('Router', ['navigate']);
spyRouter.navigate.and.returnValue(Promise.resolve({}));
const spyClientsService = jasmine.createSpyObj('ClientsService', ['deactivateClient']);
const successDeativation = {};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
ClientDeactivateComponent,
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [
HttpClientModule,
RouterTestingModule.withRoutes([{path: '**', component: ClientDeactivateComponent}])
],
providers: [
FormBuilder,
ClientsService
]
}).overrideComponent(ClientDeactivateComponent, {
set: {
providers: [
{provide: Router, useValue: spyRouter},
{provide: ClientsService, useValue: spyClientsService},
{provide: MatDialog, useValue: spyMatDialog},
{provide: Router, useValue: spyRouter},
{provide: ActivatedRoute, useValue: {params: from([{id: 1}])}}
],
template: '<div>Overridden template</div>'
}
}
)
.compileComponents();
}));
afterEach(() => {
spyMatDialog.open.calls.reset();
spyRouter.navigate.calls.reset();
spyClientsService.deactivateClient.calls.reset();
fixture.detectChanges();
});
beforeEach(() => {
fixture = TestBed.createComponent(ClientDeactivateComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
describe('default', () => {
/* this works! */
it('should create', () => {
expect(component).toBeTruthy();
});
/* Why isn't this working? */
it('should open a modal window when confirmDeactivation is called', () => {
component.confirmDeactivation();
spyClientsService.deactivateClient.and.returnValue(successDeativation);
expect(spyMatDialog.open).toHaveBeenCalledWith(ConfirmDialogComponent);
});
});
});
The first test passes as expected however the second test fails giving the following error:
TypeError: Cannot read property 'componentInstance' of undefined
I have looked at many answers here and what I have applied to try and fix this hasn't worked. I am sure it is something to do with how the testbed is loaded but I can't determine what is wrong and why?
Upvotes: 2
Views: 14255
Reputation: 15321
I found out the problem. The error message Cannot read property 'componentInstance' of undefined made me focus on the
component = fixture.componentInstance;
This was not the case, the mock of my Modal, spyMatDialog, was incorrecly mocked! The code below shows how the spyMatDialog was correctly mocked:
describe('ClientDeactivateComponent', () => {
let component: ClientDeactivateComponent;
let fixture: ComponentFixture<ClientDeactivateComponent>;
let spyDialogRef: any;
const spyRouter = jasmine.createSpyObj('Router', ['navigate']);
spyRouter.navigate.and.returnValue(Promise.resolve({}));
const spyClientsService = jasmine.createSpyObj('ClientsService', ['deactivateClient']);
spyClientsService.deactivateClient = () => of(true);
spyDialogRef = jasmine.createSpy();
spyDialogRef.componentInstance = {title: '', message: ''};
spyDialogRef.afterClosed = () => of(true);
const spyMatDialog = jasmine.createSpyObj('MatDialog', ['open']);
spyMatDialog.open.and.returnValue(spyDialogRef);
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
ClientDeactivateComponent,
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [
HttpClientModule,
RouterTestingModule.withRoutes([{path: '**', component: ClientDeactivateComponent}])
],
providers: [
FormBuilder,
ClientsService
]
}).overrideComponent(ClientDeactivateComponent, {
set: {
providers: [
{provide: Router, useValue: spyRouter},
{provide: ClientsService, useValue: spyClientsService},
{provide: MatDialog, useValue: spyMatDialog},
{provide: Router, useValue: spyRouter},
{provide: ActivatedRoute, useValue: {params: from([{id: 1}])}}
],
template: '<div>Overridden template</div>'
}
}
)
.compileComponents();
}));
afterEach(() => {
spyRouter.navigate.calls.reset();
fixture.detectChanges();
});
beforeEach(() => {
fixture = TestBed.createComponent(ClientDeactivateComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
describe('default', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
it('should open a modal window when confirmDeactivation is called', () => {
component.confirmDeactivation();
expect(spyMatDialog.open).toHaveBeenCalled();
});
});
});
Upvotes: 2