I am codng ia Unit Test on a code and component working. I can't understand what's going on. I have tried different approaches but I always get the same error. I have simplified the Code of the Unit Test to the maximum so that you can see the problem more easily. Thank you
COMPONENT
openUpdate(rowSelected: iData) {
let dialogRef = this.dialog.open(DialogEditComponent, {});
dialogRef.componentInstance.dialogRef = dialogRef;
dialogRef.componentInstance.selectedData = rowSelected;
const sub = dialogRef.componentInstance.onAdd.subscribe((data: iData) => {
if (data) {
this.update(data);
}
});
dialogRef.afterClosed().subscribe(() => {
sub.unsubscribe();
});
}
SPEC.TS
beforeEach(async () => {
const dialogSpy = {
open: jasmine.createSpy('open').and.returnValue({
componentInstance: {
onAdd: jasmine.createSpyObj('onAdd', ['subscribe'])
},
afterClosed: () => {
return jasmine.createSpyObj('afterClosed', ['subscribe']);
}
})
};
toastrServiceSpy = jasmine.createSpyObj('ToastrService', ['success', 'error']);
await TestBed.configureTestingModule({
declarations: [Component1, DialogEditComponent],
imports: [MatDialogModule, BrowserAnimationsModule],
providers: [
{ provide: MatDialog, useValue: dialogSpy },
{ provide: ToastrService, useValue: toastrServiceSpy },
{ provide: MAT_DIALOG_DATA, useValue: {} },
],
}).compileComponents();
});
........
it('should open the edit dialog with the selected data', async () => {
await component.openUpdate(mockData[0]);
expect(dialogSpy.open).toHaveBeenCalled();
});
ERROR
TypeError: Cannot read property 'open' of undefined
at UserContext.<anonymous> (src/app/features/component1.component.spec.ts:99:22)
at Generator.next (<anonymous>)
at asyncGeneratorStep (node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:3:1)
at apply (node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:22:1)
at _ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:409:30)
at ProxyZoneSpec.onInvoke (node_modules/zone.js/dist/zone-testing.js:303:43)
at _ZoneDelegate.invoke (node_modules/zone.js/dist/zone.js:408:56)
at Zone.run (node_modules/zone.js/dist/zone.js:169:47)
at apply (node_modules/zone.js/dist/zone.js:1326:38)
at _ZoneDelegate.invokeTask (node_modules/zone.js/dist/zone.js:443:35)
When you see the issue in the .spec.ts
file like so, it means open
is undefined
in your unit test (not component file so the mocking is most likely done properly).
TypeError: Cannot read property 'open' of undefined
at UserContext.<anonymous> (src/app/features/component1.component.spec.ts:99:22)
I bet the issue is the way you declare dialogSpy
.
Do the following (pay attention to comments with !!):
// !! Declare dialogSpy outside of the first `beforeEach` so all `it` blocks
// will have access to it.
let dialogSpy: any;
beforeEach(async () => {
// !! Remove const here and assign dialogSpy to what it should be
dialogSpy = {
open: jasmine.createSpy('open').and.returnValue({
componentInstance: {
onAdd: jasmine.createSpyObj('onAdd', ['subscribe'])
},
afterClosed: () => {
return jasmine.createSpyObj('afterClosed', ['subscribe']);
}
})
};
toastrServiceSpy = jasmine.createSpyObj('ToastrService', ['success', 'error']);
await TestBed.configureTestingModule({
declarations: [Component1, DialogEditComponent],
imports: [MatDialogModule, BrowserAnimationsModule],
providers: [
{ provide: MatDialog, useValue: dialogSpy },
{ provide: ToastrService, useValue: toastrServiceSpy },
{ provide: MAT_DIALOG_DATA, useValue: {} },
],
}).compileComponents();
});
it('should open the edit dialog with the selected data', async () => {
await component.openUpdate(mockData[0]);
// !! Log out dialogSpy and make sure it is not undefined
console.log(dialogSpy);
expect(dialogSpy.open).toHaveBeenCalled();
});