angularjestjsjest-preset-angular

Angular w/Jest: `verify()` vs.`expectOne()`?


I have a failing test that I'm not sure how to fix. The error messages I'm getting from Jest appear to be contradictory, and the problem relates to the behavior of two Angular HttpTestingController methods: verify() and expectOne().

The test in question, in the context of its file:

import {TestBed, getTestBed} from '@angular/core/testing';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {PrintProjectsService} from './print-projects.service';
import {AppConfig} from '../../app.config';

describe('PrintProjectsService', () => {
  let injector: TestBed;
  let service: PrintProjectsService;
  let appConfig: AppConfig;
  let httpMock: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [PrintProjectsService, AppConfig]
    });
    injector = getTestBed();
    service = injector.get(PrintProjectsService);
    httpMock = injector.get(HttpTestingController);
    appConfig = injector.get(AppConfig);
  });

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

  //This test passes
  it('should make a GET request to retrieve a printable factory when provided a printable factory id', () => {
    const id = '12345';
    service.getPrintableFactory(id).subscribe();
    const req = httpMock.expectOne(`${appConfig.API_URL}/api/printed-book/v1/printable-factories/${id}/`);
    expect(req.request.method).toBe('GET');
  });

  // This is the one that fails
  it('should make a GET request to retrieve cover image data from the cover service', () => {
    const imageType = 'full';
    service.getCoverImage(12345, '0850X1100FCSTDCO080CW444GXX', imageType).subscribe();
    //httpMock.verify(); //this finds a GET at undefined/cover/api/cover-images/full
    const req = httpMock.expectOne(`${appConfig.API_URL}/cover/api/cover-images/${imageType}`);
    expect(req.request.responseType).toBe('blob');
  });
});

Jest returns this error message:

● PrintProjectsService › should make a GET request to retrieve cover image data from the cover service

Expected one matching request for criteria "Match URL: undefined/cover/api/cover-images/full", found none.

  44 |     service.getCoverImage(12345, '0850X1100FCSTDCO080CW444GXX', imageType).subscribe();
> 45 |     const req = httpMock.expectOne(`${appConfig.API_URL}/cover/api/cover-images/${imageType}`);
  46 |     expect(req.request.responseType).toBe('blob');

  at HttpClientTestingBackend.Object.<anonymous>.HttpClientTestingBackend.expectOne (node_modules/@angular/common/bundles/common-http-testing.umd.js:435:19)
  at src/app/services/print-projects/print-projects.service.spec.ts:45:26
  ...
  at Object.testBody.length (node_modules/jest-zone-patch/index.js:50:27)

● PrintProjectsService › should make a GET request to retrieve cover image data from the cover service

Expected no open requests, found 1: GET undefined/cover/api/cover-images/full

  23 |   afterEach(() => {
> 24 |     httpMock.verify();
  25 |   });

The fact that the URL variables render to undefined in the error messages is irrelevant - that's the case within the passing tests as well.

What's confusing me is that when expectOne() is reached within the test, no request can be found for undefined/cover/api/cover-images/full, but after the test, verify() finds a GET request at the identical URL: undefined/cover/api/cover-images/full. verify() also finds a GET request at undefined/cover/api/cover-images/full when placed within the test on the line before expectOne().

Why doesn't expectOne() catch the request but verify() does? Is the error message not telling me everything I need? I seem to be getting the same error messages back regardless of whether I run jest or jest --verbose.


Solution

  • I found a way around the issue with a variant of expectOne() gleaned from here: https://github.com/thymikee/jest-preset-angular/blob/master/example/src/app/service/hero.service.spec.ts#L59

    Here is the new, passing version of the test:

    it('should make a GET request to retrieve cover image data from the cover service', () => {
        const imageType = 'full';
        service.getCoverImage(12345, '0850X1100FCSTDCO080CW444GXX', imageType).subscribe();
        const req = httpMock.expectOne((request: HttpRequest<Blob>) => {
          return request.url === `${appConfig.API_URL}/cover/api/cover-images/${imageType}`;
        });
        expect(req.request.method).toBe('GET');
        // the original `expect()` below also passes, but since we already state that the request will return a Blob above, the `expect()` above is a better option
        // expect(req.request.responseType).toBe('blob'); 
      });
    

    It appears as though the url match-only version of expectOne(), as was being used originally, expects a JSON response by default. In any case, the Blob response type of this particular call appears to have been the source of the problem.