2

I am trying to test retry on a failed httpClient post request without using a for loop and I am having a hard time finding an example of doing so. Most solutions seem to show the for loop method.

Here is the service code and test in question. This currently works as expected, how can I do it the rxjs observable functional way?

Service code:

public getUsers(): Observable<UsersResponse> {
    return this.httpClient.post<UsersResponse>(`${usersUrl}/fetchall`, '').pipe(
      retry(3),
      catchError(() => {
        return of({} as UsersResponse)
      }),
    )
  }

Test:

  it('getUsers should return an empty value on error', () => {
    sub = usersService
      .getUsers()
      .pipe(
        tap((res) => {
          expect(res).toEqual({} as UsersResponse)
        }),
      )
      .subscribe()
    for (let i = 0, c = retryCount + 1; i < c; i++) {
      const req = httpMock.expectOne('/api/fetchall')
      req.flush({}, { status: 404, statusText: 'Not Found' })
    }
  })
uber_n00b
  • 163
  • 2
  • 12
  • I am not sure if `returnValues` would help you out. https://stackoverflow.com/questions/26898613/how-to-have-different-return-values-for-multiple-calls-on-a-jasmine-spy – Get Off My Lawn Mar 14 '23 at 00:28

1 Answers1

-2

Much easier than you think. Use toHaveBeenCalledTimes. An example is below:


describe('getUsers', () => {

   beforeEach(() => {
      service.getUsers().subscribe();
   });

   it('should retry 3 times if service returns error', () => {
      const getUsersSpy = spyOn(service, 'getUsers').and.returnValue(Observable.throw({status: 404}));
      expect(getUsersSpy).toHaveBeenCalledTimes(3)
   });


});
jburtondev
  • 2,827
  • 1
  • 14
  • 20
  • It's not the `service.getUsers` which is being called 3 times, it's the http request. – František Žiačik Mar 13 '23 at 21:19
  • Incorrect, the service uses the http client module. So it is calling it. – jburtondev Mar 13 '23 at 21:26
  • Thanks for replying @jburtondev this does not appear to work. – uber_n00b Mar 14 '23 at 12:07
  • This could (possibly) work if `httpClient.post` was spied on instead. But for me it looks better @uber_n00b the way you have it written because it's more a behavioral test. Maybe I'd just remove the for cycle and just write `httpMock.expectOne(...).flush(...)` 4 times, for better clarity. – František Žiačik Mar 15 '23 at 10:45