6

I want to test 3 requests done inside a pipeline. Simplified example:

    httpClient.get<Data[]>(testUrl)
      .pipe(
        mergeMap(() => range(0, 2)),
        mergeMap(() => httpClient.get<Data[]>(testUrl)),
      )

I'm using the official recommendation: HttpTestingController. It works fine if I have the requests one after another with httpTestingController.match. However, that's not how my real app is written. It's using pipes.

    let testData: Data[] = [
      { name: 'bob' }, { name: 'carol' },
      { name: 'ted' }, { name: 'alice' }
    ];

    // Make three requests in a row
    httpClient.get<Data[]>(testUrl)
      .subscribe(d => expect(d.length).toEqual(0, 'should have no data'));

    httpClient.get<Data[]>(testUrl)
      .subscribe(d => expect(d).toEqual([testData[0]], 'should be one element array'));

    httpClient.get<Data[]>(testUrl)
      .subscribe(d => expect(d).toEqual(testData, 'should be expected data'));

    // get all pending requests that match the given URL
    const requests = httpTestingController.match(testUrl);
    expect(requests.length).toEqual(3);

    // Respond to each request with different results
    requests[0].flush([]);
    requests[1].flush([testData[0]]);
    requests[2].flush(testData);

How to make httpTestingController.match work with multiple HTTP requests inside a pipe?

This is what I have tried so far and here is the reproducible example:

    httpClient.get<Data[]>(testUrl)
      .pipe(
        mergeMap(() => range(0, 2)),
        mergeMap(() => httpClient.get<Data[]>(testUrl)),
      )
      .subscribe(d => expect(d.length).toEqual(0, 'should have no data')); 

    const requests = httpTestingController.match(testUrl);
    console.log({requests}); // <--- why only one instead of 3??

    requests[0].flush([]);
    // requests[1].flush([]); // This is undefined. How do I flush the other two requests?
    // requests[2].flush([]);  // undefined. 

    // Error: Expected no open requests, found 2: GET /data, GET /data

https://stackblitz.com/edit/angular-http-testing2?file=src%2Ftesting%2Fhttp-client.spec.ts

Adrian
  • 9,102
  • 4
  • 40
  • 35
  • perhaps you'e looking for the rxjs forkJoin - "‘forkJoin’ waits for each HTTP request to complete" - https://medium.com/@swarnakishore/performing-multiple-http-requests-in-angular-4-5-with-forkjoin-74f3ac166d61 – bob.mazzo Jun 24 '20 at 20:22
  • @bob.mazzo yes, I actually use forkJoin on my real app. But to simplify the issue and provide a minimal reproducible example I'm using mergeMap. Both fail anyways :(. I don't know how to make it work with `httpTestingController.match` or multiple `httpTestingController.expectOne`. Any ideas? You can fork the Stackblitz and see if you can make it work – Adrian Jun 24 '20 at 20:35

1 Answers1

5

And docs say:

// get all pending requests that match the given URL
const requests = httpTestingController.match(testUrl);

So you get one request, cause only one is pending. Rest will become pending when first request is completed. So to test it you go step by step.

let sentCount = 1;
httpClient.get<Data[]>(testUrl)
  .pipe(
    mergeMap(() => range(0, 2)),
    tap(() => sentCount++),
    mergeMap(() => httpClient.get<Data[]>(testUrl)),
  )
  .subscribe(d => expect(d.length).toEqual(0, 'should have no data')); 

const requests = httpTestingController.match(testUrl);
expect(sentCount).toBe(1);
requests[0].flush([]);
expect(sentCount).toBe(3);
httpTestingController.match(testUrl);
Petr Averyanov
  • 9,327
  • 3
  • 20
  • 38