Alex
Alex

Reputation: 802

Angular 5 Unit Testing cannot read property 'http' of undefined

I am attempting to write a helper function in an Angular test leveraging HttpTestingController. The reason being is because I will eventually have a series of endpoints within my Angular service, RequestService, that I want to test within this testing file. I do not want to repeatedly inject my RequestService and HttpTestingController instances into each test function that tests the service. That is redundant. Rather, I would prefer to have a single test function that takes the injected RequestService and HttpTestingController instances and repeatedly passes them into the helper function I have created, requestHelper. This way when I want to test additional endpoints, all I need to do is make a call to the helper function and provide the parameters that are needed.

The problem I am bumping into is that when the helper function runs, the service's instance for some reason does not appear to exist, Even though the test is able to access the service's functions. When it reaches my service method's call to the http.get within the callEndpoint function, it gives me the below error:

Failed: Cannot read property 'http' of undefined

This does not make sense to me because the this keyword is referring to the instance of the Angular service, and the test case is able to reach the service's function, so how could this possibly be undefined?

Here is my test spec:

import { TestBed, async, inject } from '@angular/core/testing';
import { HttpClientModule, HttpRequest, HttpParams } from '@angular/common/http';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import {  RequestService } from './request.service';

describe(`RequestService`, () => {

      beforeEach(async(() => {
        TestBed.configureTestingModule({
          imports: [
            HttpClientModule,
            HttpClientTestingModule
          ],
          providers: [
            RequestService
          ]
        });
      }));

      afterEach(async(inject([HttpTestingController], (backend: HttpTestingController) => {
        backend.verify();
      })));

      it(`TESTING INJECTION`, async(inject([RequestService, HttpTestingController],
        (service: RequestService, backend: HttpTestingController) => {

         requestHelper(service.callEndpoint,'https://endpointurl.com',backend);
      })));

      function requestHelper(serviceCall: Function, url: string,  backendInstance: any) {
        serviceCall(...serviceParams).subscribe();
        backendInstance.expectOne((req: HttpRequest<any>) => {
          return req.url === url
              && req.method === 'GET';
        }, 'GET');
      }
});

And the respective service that the spec is testing

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';

    @Injectable()
    export class RequestService {

      private requestOptions = {
        headers: new HttpHeaders({'Locale': 'en_US'})
      };

      constructor(private http: HttpClient) { }

      callEndpoint(state: string, countryCode: string): Observable<Object> {
        return this.http.get(`https://endpointurl.com`,this.requestOptions);
      }
}

Thank you for your help!

Upvotes: 0

Views: 1276

Answers (1)

Boris Lobanov
Boris Lobanov

Reputation: 2454

You can bind the context in the it block:

it(`TESTING INJECTION`, async(inject([RequestService, HttpTestingController],
    (service: RequestService, backend: HttpTestingController) => {

    requestHelper(service.callEndpoint.bind(service),'https://endpointurl.com',backend);
})));

Upvotes: 1

Related Questions