6

I m writing a Uni-test for a login Method with an HTTP.post call, like:

this.http.post( endpoint, creds, { headers: headers})
        .map(res => res.json())
        .subscribe(
        data => this.onLoginComplete(data.access_token, credentials),  
        err => this.onHttpLoginFailed(err),
        () => this.trace.debug(this.componentName, "Login completed.")
    );

The problem is that i'm not able to simulate the error branch; everytime is called the onLoginComplete Method;

here is my test:

it("check that  Atfer Login, console show an error ", inject(
  [TraceService, Http, MockBackend, WsiEndpointService],
  (traceService: TraceService, http: Http, 
   backend: MockBackend, wsiEndpoint: WsiEndpointService) => {

  let tokenTest: number =  404 ;

  let response: ResponseOptions = null {} // i think i have to modify this

  let connection: any;

  backend.connections.subscribe((c: any) => connection = c);

  let authService: AuthService = new AuthService(http, Service1, Service2);

  authenticationservice.login({ "username": "a", "password": "1" });

  connection.mockRespond(new Response(response));

  expect(ERROR);

}));

Thanks again to everyone.

AntuJitsu
  • 119
  • 1
  • 9

2 Answers2

18

First you need to override the XHRBackend class by the MockBackend one:

describe('HttpService Tests', () => {
  beforeEachProviders(() => {
    return [
      HTTP_PROVIDERS,
      provide(XHRBackend, { useClass: MockBackend }),
      HttpService
    ];
  });

  (...)
});

Notice that HttpService is the service that uses the Http object and I want to test.

Then you need to inject the mockBackend and subscribe on its connections property. When a request is sent, the corresponding callback is called and you can specify the response elements like the body. The service will receive this response as the response of the call. So you'll be able to test your service method based on this.

Below I describe how to test the getItems method of the HttpService:

it('Should return a list of items', inject([XHRBackend, HttpService, Injector], (mockBackend, httpService, injector) => {
  mockBackend.connections.subscribe(
    (connection: MockConnection) => {
      connection.mockRespond(new Response(
        new ResponseOptions({
          body: [ { id: '1', label: 'item1' }]
        })));
      });

  httpService.getItems().subscribe(
    items => {
      expect(items).toEqual([ { id: '1', label: 'item1' }]);
    });
  });
});

Here is the code of getItems method of the HttpService:

@Injectable()
export class HttpService {
  constructor(private http:Http) {
  }

  getItems(): Observable<any[]> {
    return this.http.get('/items').map(res => res.json());
  }
}

To simulate an error simply use the mockError method instead of the mockResponseone:

  mockBackend.connections.subscribe(
    (connection: MockConnection) => {
      connection.mockError(new Error('some error'));
    });
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • 11
    Small question: How would you add an error http status code (404, 422, 500, etc) with mockError, besides the string? In my case, some server responses won't return anything but that. For some reason I haven't found an example that shows that anywhere. – Lucio Mollinedo Apr 27 '16 at 01:46
  • 1
    @LucioMollinedo that's because it's not supported in current RC. See https://github.com/angular/angular/pull/8961 for the bug fix to make this available. In the meantime, poor unit tests going to have to take another hit. – Fiddles Aug 08 '16 at 05:30
  • I am wondering whether this solution can be applied to the current version of angular (2.4)? I tried to adapt it here: http://stackoverflow.com/questions/42192911/ to no avail... Can someone please advise? – balteo Feb 15 '17 at 18:48
2

You can simulate an error like this:

connection.mockError(new Response(new ResponseOptions({
    body: '',
    status: 404,
})));

I created a small class

import {ResponseOptions, Response} from '@angular/http';

export class MockError extends Response implements Error {

    name: any;
    message: any;

    constructor(status: number, body: string = '') {
        super(new ResponseOptions({status, body}));
    }
}

which can use like this

connection.mockError(new MockError(404));
tschuege
  • 761
  • 1
  • 8
  • 20