efarley efarley - 1 month ago 13
HTTP Question

Angular 2 RC6 test HTTP.get throws error the get() method doesn't exist

I am trying to write a unit test for a method that includes an http.get method and I'm having issues getting it to work. I know that setting the class to use for Http as MockBackend is wrong and is why I get the error:

get() method does not exist
however I don't know what I should use for the mock class behind http.

describe('Http Service', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
SharedHttpService,
{
provide: SharedCookieService,
useClass: MockSharedCookieService
}, {
provide: Http,
useClass: MockBackend
}
]
});
});

beforeEach(inject([ SharedHttpService, Http ], ( _httpService: SharedHttpService, _mockBackend: MockBackend ) => {
httpService = _httpService;
mockBackend = _mockBackend;
}));

describe('get', () => {
it(`should call setAuthToken and make the get request with the authorization headers`, () => {
let fakeUrl: string = 'www.fakeurl.com';
httpService.headers = mockHeaders;
spyOn(httpService, 'setAuthToken');
spyOn(httpService.http, 'get').and.callThrough();
mockBackend.connections.subscribe((connection: MockConnection) => {
let options: ResponseOptions = new ResponseOptions({
body: { }
});
connection.mockRespond(new Response(options));
});
httpService.get(fakeUrl, () => { })
.subscribe(() => {
expect(httpService.setAuthToken).toHaveBeenCalled();
expect(httpService.http.get).toHaveBeenCalledWith(fakeUrl, { headers: mockHeaders });
});
});
});


Code behind:

export class SharedHttpService {
private headers: Headers = new Headers();

constructor( private cookieService: SharedCookieService,
private http: Http ) { }

public get(address: string, callback: any): Observable<any> {
return this.setAuthToken()
.map(() => { })
.switchMap(() => {
return this.http.get(address, { headers: this.headers })
.map(callback)
.catch(( error: any ) => this.handleError(error));
});
}
}

Answer

You need to use the MockBackend not as the Http, but to create the Http. You do that with a factory

imports: [ HttpModule // this is needed ],
providers: [
  SharedHttpService,
  MockBackend,
  BaseRequestOptions    // @angular/http
  {
    provide: Http,
    deps: [ MockBackend, BaseRequestOptions ],
    useFactory: (backend: MockBackend, options: BaseRequestOptions) => {
      return new Http(backend, options);
    }
  }
]

Now you can inject the MockBackend into the tests so that you can mock the response on the connection.

                                  // MockBackend not Http
beforeEach(inject([ SharedHttpService, MockBackend ],
          ( _httpService: SharedHttpService, _mockBackend: MockBackend ) => {
  httpService = _httpService;
  mockBackend = _mockBackend;
}));

Another thing, you need to use an asynchronous test, as the call to subscribe resolves asynchronously

import { async } from '@angular/core/testing';

it('...', async(() => {

}));

See also Angular 2 Testing - Async function call - when to use

Comments