Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jasmine HTTP tests not getting coverage on RXJS pipeline

Problem

Hey everyone, I'm adding some Karma-Jasmine unit-testing to my Angular 2 project and I cannot for the life of me get the coverage to hit the RXJS operators in my service methods.

The tests are using the HttpClientTestingModule and HttpTestingController.

Code

Here's a simple example just using the map operator.

MyService:

getAssetCount(): Observable<AssetModel[]> {
  return this.http
    .get('/myproject/v1/asset-count')
    .pipe(map(response => response as AssetModel[]));
}

MyService.spec:

service = testBed.get(MyService);
httpMock = testBed.get(HttpTestingController);
...

it('should getAssetCount', () => {
  const dummyResponse = [{...}];
  service.getAssetCount().subscribe((response: AssetModel[]) => {
    expect(response).toEqual(dummyResponse);
    const req = httpMock.expectOne(
      '/myproject/v1/asset-count'
    );
    expect(req.request.method).toBe('GET');
    req.flush(dummyResponse);
    httpMock.verify();
  });
});

Result

The resulting coverage:

The resulting coverage

I would have thought having a subscription to the observable in the test would trigger the map() call, but perhaps I'm misunderstanding how these mock services work.

From looking around, it seems like switching to the XHRBackend instead of the HttpClientTestingModule to generate dummy 200/404/etc responses could solve the issue, but besides being more boilerplate, it seems like most people were suggesting to use the TestingModule instead.

like image 223
Robert Lee Avatar asked Feb 06 '19 18:02

Robert Lee


People also ask

How do I get karma code coverage?

To enable this, open the Karma test platform configuration file, karma. conf. js , and add the check property in the coverageReporter: key. The check property causes the tool to enforce a minimum of 80% code coverage when the unit tests are run in the project.

What does detectChanges do in Angular Jasmine tests?

detectChanges() tells Angular to run change-detection. Finally! Every time it is called, it updates data bindings like ng-if, and re-renders the component based on the updated data. Calling this function will cause ngOnInit to run only the first time it is called.


1 Answers

Try moving the flush() and other testing logic outside of the subscribe, just leaving the expect(response) inside. Something like this:

it('should getAssetCount', () => {
  const dummyResponse = [{...}];
  service.getAssetCount().subscribe((response: AssetModel[]) => {
    expect(response).toEqual(dummyResponse);
  });
  const req = httpMock.expectOne(
    '/myproject/v1/asset-count'
  );
  expect(req.request.method).toBe('GET');
  req.flush(dummyResponse);
  httpMock.verify();
});
like image 139
dmcgrandle Avatar answered Nov 15 '22 05:11

dmcgrandle