I'm trying to unit test a function inside a component, this function is called from ngOnInit based on an inital condition:
ngOnInit() {
if (this.list.length === 0) {
return this.loadData();
}
return this.isLoading = false;
}
// I'm calling here because it could also be called from button on the UI
loadData() {
this.apiService.apiGet().subscribe((response) => {
// handle data
return this.isLoading = false;
}, (error) => {
// handle error
return this.isLoading = false;
})
}
But I'm not able to test it unless I call the function manually on the tests. This is my test code:
// THIS CODE WORKS
it('should be false after calling loadData()', async(() => {
component.loadData();
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.isLoading).toBeFalsy();
});
}));
// THIS CODE DOESN'T work
it('should be false after calling loadData()', async(() => {
spyOn(component,'loadData').and.returnValue({code:'success'});
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.isLoading).toBeFalsy();
});
}));
Also this is the piece of code I'm using to mock the apiGet function:
apiGet() {
return Observable.of({ data: 'success' });
}
However I know the ngOnInit is being executed and the function is being called because this test pass:
it('should be called if list array is empty', () => {
spyOn(component,'loadData').and.returnValue({code:'success'});
fixture.detectChanges();
expect(component.loadData).toHaveBeenCalled();
});
What am I doing wrong? Why the test failling doesn't get to the ending promise?
This mocked method doesn't set isLoading
, while it returns a value which is irrelevant here:
spyOn(component,'loadData').and.returnValue({code:'success'});
So its behaviour clearly differs from the real method. If this means that this makes this expectation false, then that's it:
expect(component.isLoading).toBeFalsy();
The proper way to test this is to test this in several isolated specs, line by line:
// ngOnInit test
spyOn(component, 'loadData');
this.list.length = 0;
fixture.detectChanges();
expect(component.loadData).toHaveBeenCalled();
expect(component.isLoading).toBe(true);
// ngOnInit test
spyOn(component, 'loadData');
this.list.length = 1;
fixture.detectChanges();
expect(component.loadData).not.toHaveBeenCalled();
expect(component.isLoading).toBe(false);
// loadData test
const apiServiceMock = {
apiGet: jasmine.createSpy().and.returnValue(Observable.of(...))
};
this.apiService = apiServiceMock; // or mock via DI
spyOn(component, 'loadData').andCallThrough();
fixture.detectChanges();
// OR
// component.loadData()
expect(component.loadData).toHaveBeenCalled();
expect(apiServiceMock.apiGet).toHaveBeenCalled()
expect(component.isLoading).toBe(false);
// loadData test
const apiServiceMock = {
apiGet: jasmine.createSpy().and.returnValue(Observable.throw(...))
};
// the rest is same
// loadData test
const apiServiceMock = {
apiGet: jasmine.createSpy().and.returnValue(Observable.empty())
};
fixture.detectChanges();
expect(component.loadData).toHaveBeenCalled();
expect(apiServiceMock.apiGet).toHaveBeenCalled()
expect(component.isLoading).toBe(true);
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