Home > database >  Angular testing: Why is there no race condition involved in while mocking HTTP calls in the given ex
Angular testing: Why is there no race condition involved in while mocking HTTP calls in the given ex

Time:10-27

Consider the following short test case mentioned here:

describe('FlickrService', () => {
  let flickrService: FlickrService;
  let controller: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [FlickrService],
    });
    flickrService = TestBed.inject(FlickrService);
    controller = TestBed.inject(HttpTestingController);
  });

  it('searches for public photos', () => {
    let actualPhotos: Photo[] | undefined;
    flickrService.searchPublicPhotos(searchTerm).subscribe(
      (otherPhotos) => {
        actualPhotos = otherPhotos;
      }
    );

    const request = controller.expectOne(expectedUrl);
    request.flush({ photos: { photo: photos } });
    controller.verify();

    expect(actualPhotos).toEqual(photos);
  });
});

My question is how can we guarantee that the expectation expect(actualPhotos).toEqual(photos) would run before the observable flickrService.searchPublicPhotos's next method is called. Won't there be a race condition, and shouldn't we be using tick() before making the assert call

CodePudding user response:

It depends on how searchPublicPhotos is implemented. If it is emitting right away (like with of()) it will work but if it's asynchronous (like a http call or even a delay(0)) your subscribe will trigger after your expect check. Since you probably don't want to rely on the implementation that much it is not advised to use it like this. Instead you can use jest's done call back for testing asynchronous code:

it('searches for public photos', done => {
    flickrService.searchPublicPhotos(searchTerm).subscribe(actualPhotos => {
        expect(actualPhotos).toEqual(photos);
        done();
    });

    const request = controller.expectOne(expectedUrl);
    request.flush({ photos: { photo: photos } });
    controller.verify();
});

If done() isn't called the test will fail.

  • Related