3

I'm trying to test a retryWhen operator in an http interceptor but I'm getting an error when trying to repeat my service call multiple times:

"Error: Expected one matching request for criteria "Match URL: http://someurl/tesdata", found none."

So I have 2 questions. First, am I going about testing this in the right way and second, why can I not make multiple service requests without getting a match error?

My interceptor works fine and is using rxjs retryWhen operator eg:

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).pipe(
        retryWhen(errors => errors
            .pipe(
            concatMap((err:HttpErrorResponse, count) => iif(
            () => (count < 3),
            of(err).pipe(
                delay((2 + Math.random()) ** count * 200)),
                throwError(err)
            ))
        ))
    );
  }
}

My test service:

import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class InterceptorTestService {

  constructor(private httpClient: HttpClient) { }

  getSomeData() : Observable<boolean>{
    return this.httpClient
      .get('http://someurl/tesdata').pipe(
        map(()=>{
          return true;
        })
      )
  }
}

My spec:


import { InterceptorTestService } from './interceptor-test.service';
import { HttpClientTestingModule, HttpTestingController, TestRequest } from '@angular/common/http/testing';

describe('InterceptorTestService', () => {

  let service: InterceptorTestService;
  let backend: HttpTestingController;


  beforeEach(() => TestBed.configureTestingModule({
    providers: [InterceptorTestService],
    imports: [HttpClientTestingModule]
  }));

  beforeEach(() =>{
    service = TestBed.get(InterceptorTestService),
    backend = TestBed.get(HttpTestingController)
  });

  it('should be created', () => {
    service.getSomeData().subscribe();


    const retryCount = 3;
    for (var i = 0, c = retryCount + 1; i < c; i++) {
      let req = backend.expectOne('http://someurl/tesdata');
      req.flush("ok");
    }
  });
});
BWG
  • 304
  • 3
  • 15

1 Answers1

2

I just had exactly the same issue and have solved after reading this SO answer and adapting it to my needs:

Angular 7 testing retryWhen with mock http requests fails to actually retry

The key parts being adding:

  1. tick(2500) after each flush
  2. Making the test fakeAsync (so you can use tick).

This is how my test looks now for reference just in case it helps you get where you're going (apologies for not adapting it perfectly for your needs):

it("addLicensedApplication() should return an error command result if an error occurs", fakeAsync(() => {
  let errResponse: any;
  const mockErrorResponse = { status: 400, statusText: "Bad Request" };

  service
    .addLicensedApplication(aCompanyId, LicensedApplicationFlag.workshopPro)
    .subscribe(res => res, err => errResponse = err);

  const retryCount = 5;
  for (let i = 0, c = retryCount + 1; i < c; i += 1) {
    const req = httpMock
      .expectOne(`${env.apiProtocol}${env.apiUrl}${Constants.addLicensedApplicationUrl}`);

    req.flush(CommandResultErrorFixture, mockErrorResponse);
    tick(2500);
  }

  expect(errResponse.error).toBe(CommandResultErrorFixture);
}));

afterEach(() => {
  httpMock.verify();
});
Ben Thomson
  • 1,083
  • 13
  • 29