Reputation:
I am pretty confused on how to mock that my http service catches an observable error. I have read through the angular documentation but I do not understand how I would structure the test. I would like to mock an error in my service, then check that it catches an error observable. I have another service that creates and throws the error observable. The rest of my services just catch it when encountering an error. I am honestly very confused on how to implement this. Here is a simple verison of my service, and also the error service:
getData(url: string): Observable<any> {
return this.http.get(url)
.map(this.extractData)
.catch(this.handleErrorObservable);
}
handleErrorObservable(error: Response | any) {
console.error(error.message || error);
return Observable.throw(error.message || error);
}
Now how would I simulate an error? Do I need to spy on the service and make it fail? Would something along the lines of spyOn(service, 'getData).and.returnValue(Observable.throw({status: 404})))
or am I looking at this the wrong way? Thanks.
EDIT: Code with Castro Roy's solution.
import {HttpErrorResponse, } from '@angular/common/http';
import { TestBed, inject } from '@angular/core/testing'
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'
import {HttpService} from '../services/http.service'
fdescribe('MyService', () => {
let httpTestingController: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [HttpService]
});
httpTestingController = TestBed.get(HttpTestingController);
});
afterEach(() => {
httpTestingController.verify();
});
it('should be created', inject([HttpService], (service: HttpService)=> {
expect(service).toBeTruthy();
}));
it('should handleErrorObservable', inject([HttpService], (service: HttpService) => {
const urlString = '/data';
const emsg = 'deliberate 404 error';
spyOn(service, 'handleErrorObservable').and.callThrough();
service.getData(urlString).subscribe(
data => fail('should have failed with the 404 error'),
(error: HttpErrorResponse) => {
expect(service.handleErrorObservable).toHaveBeenCalled(); // check if executed
expect(error.status).toEqual(404, 'status');
expect(error.error).toEqual(emsg, 'message');
});
const req = httpTestingController.expectOne(urlString);
req.flush(emsg, { status: 404, statusText: 'Not Found' });
}));
});
Upvotes: 7
Views: 28971
Reputation: 7823
spyOn(service, 'getData').and.returnValue(Observable.throw({status: 404})))
migth be useful if you are trying to mock getData
to some other service that use it, but handleErrorObservable
will never be executed. So, if you want to test that handleErrorObservable
have been called, something like this should help you:
import { HttpErrorResponse } from '@angular/common/http';
import { TestBed, inject } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { MyService } from './MyService';
describe('MyService', () => {
let httpTestingController: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [MyService]
});
httpTestingController = TestBed.get(HttpTestingController);
});
afterEach(() => {
// After every test, assert that there are no more pending requests.
httpTestingController.verify();
});
it('should be created', inject([MyService], (service: MyService) => {
expect(service).toBeTruthy();
}));
it('should handleErrorObservable', inject([MyService], (service: MyService) => {
const urlString = '/data';
const emsg = 'deliberate 404 error';
spyOn(service, 'handleErrorObservable').and.callThrough();
service.getData(urlString).subscribe(
data => fail('should have failed with the 404 error'),
(error: HttpErrorResponse) => {
expect(service.handleErrorObservable).toHaveBeenCalled(); // check if executed
expect(error.status).toEqual(404, 'status');
expect(error.error).toEqual(emsg, 'message');
}
});
const req = httpTestingController.expectOne(urlString);
// Respond with mock error
req.flush(emsg, { status: 404, statusText: 'Not Found' });
}));
});
Here we are using the HttpClientTestingModule
and HttpTestingController
to mock an error response with status code 404. Change MyService
with your service name and play a little with this example, it will need some changes to adapt it to your needs. More info in the docs
Also, take a look to another question where are using a different way of mocking the HttpClient
service.
Hope it helps.
Upvotes: 13