0

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?

Felipe
  • 6,312
  • 11
  • 52
  • 70

0 Answers0