I am having trouble mocking a service that returns an error in a Component's unit test file. My app is written in Angular 6 with TypeScript and my unit tests are written in Jasmine.
In my component I call a method in the ngOnInit
and within this method I call a method on a imported service, should this fail a boolean property of my component called isLoading
should be set to false. Here is some minimised code of my component to give an understanding of the code I am wishing to test.
export class CylindersListComponent implements OnInit, OnDestroy {
public isLoading: boolean = true;
public ngOnInit(): void {
// do stuff ... I have removed some code here
this.loadCylinderList();
}
public loadCylinderList() {
this.cylindersService.getCylinderList().subscribe((res: any) => {
this.cylinders = res;
// do stuff ... I have removed lots of code here
this.isLoading = false;
}, (error: any) => {
this.isLoading = false;
throw new Error(error);
});
}
}
I wish to mock the loadCylinderList
method being called and the cylindersService.getCylinderList returning an error. Thus once this is done I wish to assert (or make sure) that the isLoading
property is false. Now I have my unit test set up like so, however this doesn't seem to work (or more likely I have implemented the test incorrectly). Once again I have minimised the code or put ...
where data is returned.
describe('CylindersListComponent', () => {
let fixture: ComponentFixture<CylindersListComponent>;
let instance: CylindersListComponent;
const spyCylinderService = jasmine.createSpyObj<CylindersService>(
'CylindersService', ['getCylinderList', 'getListPaged']);
spyCylinderService.getListPaged.and.returnValue(observedData); // observedData is set earler in the file
beforeEach(async(() => {
// inject the spies. We use override component because the service is injected
// in component not in the module. (deeper level)
TestBed.overrideComponent(CylindersListComponent, {
set: {
providers: [
{provide: CylindersService, useValue: spyCylinderService}
],
template: '<input #filter>'
}
})
// prepare CylinderComponent for the tests
// Allows overriding default providers, directives, pipes
.configureTestingModule({
imports: [...],
declarations: [
CylindersListComponent
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents().then(() => {
// arrange
fixture = TestBed.createComponent(CylindersListComponent);
instance = fixture.componentInstance;
spyCylinderService.getCylinderList.and.returnValue({...});
});
}));
it('should be false after error while loading data', () => {
// arrange
spyCylinderService.getCylinderList.and.throwError('error');
instance.isLoading = true;
spyOn(instance, 'loadCylinderList' as any).and.callThrough();
// act
fixture.detectChanges();
expect(instance.isLoading).toBe(false);
});
This sounds like a very open question and I apologise but what I am doing wrong with my test / spyOn method. I am sure I am getting a failed test / error as my implementation to raise / mock the error is incorrect: spyCylinderService.getCylinderList.and.throwError('error');
If anyone can see what I am doing wrong I would be most appreciative. The error from the test console is as follows if that is of any help:
HeadlessChrome 0.0.0 (Mac OS X 10.12.6) CylindersListComponent isLoading should be false after error while loading data FAILED
Error: error
error properties: Object({ ngDebugContext: DebugContext_({ view: Object({ def: Object({ factory: Function, nodeFlags: 33800449, rootNodeFlags: 33554433, nodeMatchedQueries: 0, flags: 0, nodes: [ Object({ nodeIndex: 0, parent: null, renderParent: null, bindingIndex: 0, outputIndex: 0, checkIndex: 0, flags: 33554433, childFlags: 246016, directChildFlags: 246016, childMatchedQueries: 0, matchedQueries: Object({ }), matchedQueryIds: 0, references: Object({ }), ngContentIndex: null, childCount: 4, bindings: [ ], bindingFlags: 0, outputs: [ ], element: Object({ ns: '', name: 'cylinders', attrs: [ ], template: null, componentProvider: Object({ nodeIndex: 4, parent: <circular reference: Object>, renderParent: <circular reference: Object>, bindingIndex: 0, outputIndex: 0, checkIndex: 4, flags: 245760, childFlags: 0, directChildFlags: 0, childMatchedQueries: 0, matchedQueries: Object, matchedQueryIds: 0, references: Object, ngContentIndex: -1, childCount: 0, bindings: Array, bindingFlags: 0, outputs: Array, ...
at <Jasmine>
Update: I am sure how I am raising the error is wrong as if I should put a console.log
in the component where the error is caught nothing is written to the console.