Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular unit test - testing retryWhen in HttpInterceptor

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");
    }
  });
});
like image 965
BWG Avatar asked Oct 21 '25 12:10

BWG


1 Answers

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();
});
like image 125
Ben Thomson Avatar answered Oct 23 '25 00:10

Ben Thomson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!