Search code examples
angularasync-awaitangular-httpclient

Flushing a sequence of Angular HTTP TestRequest


I have an async function that needs to make a POST request, but some of the data must be fetched from the server first:

async createObject() {
  // HTTP request #1: dep1 is needed for the second request
  const dep1 = await this.http.get("/urlA")
    .pipe(first())
    .toPromise();
  // Create the request object out of dep1 and some additional values
  const req = mkCreateParams(this.name, dep1);
  // HTTP request #2: Build something
  const res = await this.http.post("/urlB")
    .pipe(first())
    .toPromise();
  // When everything is done: Navigate away
  this.router.navigateByUrl(`/urlC/${res.id}`);

  return res;
}

I use the following code to test this:

const httpTesting = TestBed.inject(HttpTestingController);
const req = testInstance.createObject();

httpTesting
  .expectOne("/urlA")
  .flush({ /* ... SNIP ... */);

const generatedId = "f9f64792-0ceb-4e3c-ae7b-4c7a8af6a552";
httpTesting
  .expectOne({ method: "POST", url: "/urlB" })
  .flush({ id: generatedId });

const res = await req;
expect(res.id).toEqual(generatedId);

This fails immediatly when expecting /urlB and doesn't even reach the line where res is resolved. The error message is as follows:

Expected one matching request for criteria "Match method: POST, URL: /urlB", found none.

This seems to be because a request must have been already issued when calling HttpTestingController.expectOne(). As promises are resolved eagerly in JavaScript, the first request has already been made but the second request not.

Is there a way to tell the Angular HttpTestingController to relax a little and wait for the request to come by some time later? The existance of HttpTestingController.verify hints at this, but I have no idea how to get into a state where it would be useful.


Solution

  • I think waiting for the promises can help you, try fixture.whenStable().

    it('your title here', async done => {
      const httpTesting = TestBed.inject(HttpTestingController);
      const req = testInstance.createObject();
    
      httpTesting
        .expectOne("/urlA")
        .flush({ /* ... SNIP ... */);
      await fixture.whenStable(); // wait for the pending promises to resolve before proceeding
      const generatedId = "f9f64792-0ceb-4e3c-ae7b-4c7a8af6a552";
      httpTesting
        .expectOne({ method: "POST", url: "/urlB" })
        .flush({ id: generatedId });
      await fixture.whenStable(); // wait for the pending promises to resolve before proceeding
      const res = await req;
      expect(res.id).toEqual(generatedId);
      // call done to let Jasmine know you're done with this test
      done();
    });