I have created a simple service in Angular 2 to post some data to my backend and I am in the process of writing the spec for this service. I've managed to successfully test the service when the HTTP response is 200 (ok), however I am having trouble testing what happens when the HTTP response is an error.
Here is the spec code:
import { TestBed, inject, async, fakeAsync, tick } from '@angular/core/testing';
import { BaseRequestOptions, Http, HttpModule, Response, ResponseOptions, ResponseType } from '@angular/http';
import { MockBackend, MockConnection } from '@angular/http/testing';
import { ContactService } from './contact.service';
import { Contact } from '../model/contact.model';
import { ServiceResponse } from '../model/service-response.model';
describe('ContactService', () => {
let mockBackend: MockBackend;
let service: ContactService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
ContactService,
MockBackend,
BaseRequestOptions,
{
provide: Http,
useFactory: (backend, options) => new Http(backend, options),
deps: [MockBackend, BaseRequestOptions]
}
]
});
});
// Inject the service
beforeEach(async(inject([ContactService, MockBackend], (dataService, backend) => {
service = dataService;
mockBackend = backend;
})));
it('should create the service', () => {
expect(service).toBeTruthy();
expect(mockBackend).toBeTruthy();
});
it('should post the contact data via HTTP', () => {
let result: Promise<ServiceResponse>;
const mockContactData: Contact = {
senderEmail: 'my.email@email.com',
senderName: 'John Doe',
subject: 'Lorem ipsum',
message: 'Lorem ipsum dolor sit amet'
};
// Listen and return an ok.
mockBackend.connections.subscribe(
(conn: MockConnection) => {
conn.mockRespond(new Response(new ResponseOptions(({ status: 200 }))));
});
result = service.sendContactData(mockContactData);
result.then((response: ServiceResponse) => {
expect(response.status).toEqual(200);
});
});
it('should handle any errors during the post', () => {
let result: Promise<ServiceResponse>;
const body = JSON.stringify({ message: 'Erro ao enviar e-mail' });
const opts = { type: ResponseType.Error, status: 404, body: body };
const responseOpts = new ResponseOptions(opts);
mockBackend.connections.subscribe(
(conn: MockConnection) => {
conn.mockRespond(new Response(responseOpts));
});
result = service.sendContactData(new Contact());
result.catch((response: ServiceResponse) => {
expect(response.status).toEqual(404);
});
});
});
And the service code:
import { Injectable } from '@angular/core';
import { Http, Response, RequestOptions, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/toPromise';
import { Contact } from '../model/contact.model';
import { ServiceResponse } from '../model/service-response.model';
@Injectable()
export class ContactService {
private contactServletUrl = 'http//localhost:3000/Contact';
constructor(private http: Http) { }
/**
* Sends the contact data via HTTP POST to the backend, where it will be
* processed and sent as an e-mail.
*/
sendContactData(data: Contact): Promise<ServiceResponse> {
const headers = new Headers({ 'Content-Type': 'application/json' });
const options = new RequestOptions({ headers: headers });
return this.http.post(this.contactServletUrl, { body: JSON.stringify({contact: data}) }, options).toPromise()
.then((res: Response) => {
const serviceResponse: ServiceResponse = new ServiceResponse();
serviceResponse.status = res.status;
serviceResponse.message = 'E-mail enviado com sucesso.';
serviceResponse.successs = true;
return serviceResponse;
})
.catch(this.handleError);
}
private handleError(error: Response | any): Promise<ServiceResponse> {
// In a real world app, we might use a remote logging infrastructure
let errMsg: string;
const serviceResponse: ServiceResponse = new ServiceResponse();
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
serviceResponse.status = error.status;
}
else {
errMsg = error.message ? error.message : error.toString();
}
serviceResponse.message = errMsg;
serviceResponse.successs = false;
console.error(errMsg);
return Promise.reject(serviceResponse);
}
}
The problem is that when I run the should handle any errors during the post
test, the promise is not rejected and this catch statement is never executed:
result.catch((response: ServiceResponse) => {
expect(response.status).toEqual(404);
});
What I am doing wrong? Is there a way to force the http promise to fail?