user8654991
user8654991

Reputation:

HttpTestingController.expectOne can't see my request, but it is open in afterEach() method

I am writing a unit test to test my service which is calling rest API. expectOne() fails to find my request: Expected one matching request for criteria "Match URL: http://localhost:5000/api/v1.0/stat/estimation-graph", found none.

I tried different overloads of expectOne(), such as:

httpMock.expectOne(url)
httpMock.expectOne({method: 'GET', url: url})
httpMock.expectOne(res => res.method === 'GET' && res.url === url)

Also, I tried changing URL so that is contains parameters ('http://localhost:5000/api/v1.0/stat/estimation-graph?battleCount=100&winCount=50') but with no luck.

Lastly, I opened a Chrome console with Karma test results and I found that my API can't be called due to CORS policy. I Fixed that also.

My .spec.ts file:


// imports..

describe('StatProviderService', () => {
    let injector: Injector;
    let httpMock: HttpTestingController;
    let statService: StatProviderService;
    beforeEach(() => 
    {
        injector = TestBed.configureTestingModule({
            imports: [
                HttpClientModule,
                HttpClientTestingModule,
            ],
            providers: [
                StatProviderService,
            ],
        });
        httpMock = injector.get(HttpTestingController);
        statService = injector.get(StatProviderService);
    });

    afterEach(() => {
        httpMock.verify();
    });

    it('should work', () => {
        let response;
        let url = 'http://localhost:5000/api/v1.0/stat/estimation-graph';

        statService.getEstimationGraphData( 100, 50 )
          .subscribe(res => {
            response = res;
          });

        const req = httpMock.expectOne(url);
        req.flush(response);
    });
});

My service class:


// imports...

@Injectable({
    providedIn: 'root'
})
export class StatProviderService {
    // private variables

    constructor(
        private http: HttpClient
    ) { }

    private baseApiUrl(endpoint?: string) {
        return `${this.env.apiUrl}/${this.apiVer}/${endpoint}`;
    }

    getEstimationGraphData(battlecount: number, winCount: number): Observable<IEstimationGraphPoint[]> {
        return this.http.get<IEstimationGraphPoint[]>(`${this.baseApiUrl(this.graphDataEndpoint)}/?battleCount=${battlecount}&winCount=${winCount}`);
    }
}

The Karma result window is telling me that it can't locate the open request:

Error: Expected one matching request for criteria "Match URL: http://localhost:5000/api/v1.0/stat/estimation-graph", found none.

But after adding the httpMock.verify() in the afterEach() I got the next error:

Error: Expected no open requests, found 1: GET http://localhost:5000/api/v1.0/stat/estimation-graph/

So looks like the request is called, but later than expected. As far as I subscribed to getEstimationGraphData() it should be called synchronously, right?

Upvotes: 0

Views: 1644

Answers (1)

Johns Mathew
Johns Mathew

Reputation: 812

Since you are appending the params with the URL in your service, the HttpTestingController expects the test URL also to contain the params. Instead of creating the URL with params in your service, pass them as HttpParams.

getEstimationGraphData(battlecount: number, winCount: number): Observable<IEstimationGraphPoint[]> {
  return this.http.get<IEstimationGraphPoint[]>(this.baseApiUrl(this.graphDataEndpoint), {
    params: {
      battleCount: battlecount.toString(),
      winCount: winCount.toString()
    }
  });
}

Now, in your spec file, you need to use a custom function to check for the url. Use the below code to test for the url:

const req = httpMock.expectOne((request: HttpRequest<any>) => {
  return request.url === url;
});

request.url will contain the url without the params. The actual URL with params will be in request.urlWithParams if in case you need to check the params as well.

You might also need to remove HttpClientModule from your spec file. You just need HttpClientTestingModule.

Upvotes: 1

Related Questions