Reza
Reza

Reputation: 19913

How to test retryWhen with jest on nest HttpService

I have the below method in my NestJS project:

getAccessToken(): Observable < string > {
  return this.httpService.post(`${url}/oauth2/token`, params).pipe(
    retryWhen((errors) =>
      errors.pipe(
        delay(1000),
        take(5),
        (e) =>
          concat(
            e,
            throwError(
              `Error retrieving access token. Tried 5 times.`
            )
          )
      )
    ),
    catchError((err) => {
      this.loggerService.error(err);
      throw err;
    }),
    map((res) => res.data),
    map((data) => data.access_token)
  );
}

The above code will call the API. If successful, it will return access_token, if fails it tries up to 5 times, and if not successful after 5 times, it will throw an exception.

Now I want to write 3 unit tests,

  1. Success when the API is not throwing error and return an access token

  2. Fails 6 times

  3. Fails 2 times and return access token

Test 1:

it('should return access_token', async () => {
  const response: AxiosResponse = {
    data: {
      access_token: 'token1'
    },
    status: 200,
    statusText: 'OK',
    headers: {},
    config: {}
  };

  const post = jest
    .spyOn(httpService, 'post')
    .mockImplementationOnce(() => of(response));

  try {
    const token = await service.getAccessToken().toPromise();
    expect(token).toBe('token1');
  } catch (err) {
    expect(true).toBeFalsy();
  }
});

Test 2:

it('should retry and fails', async () => {
  const err: AxiosError = {
    config: {},
    code: '500',
    name: '',
    message: '',
    response: {
      data: {},
      status: 500,
      statusText: '',
      headers: {},
      config: {}
    },
    isAxiosError: true,
    toJSON: () => null
  };

  const post = jest
    .spyOn(httpService, 'post')
    .mockImplementationOnce(() => throwError(err));

  try {
    await service.getAccessToken().toPromise();
    expect(true).toBeFalsy();
  } catch (err) {
    expect(err).toBe(
      'Error retrieving access token. Tried 5 times.'
    );
  }
});

However, I can't figure out how to write the test for the 3rd.

Upvotes: 0

Views: 2096

Answers (1)

Reza
Reza

Reputation: 19913

I found the solution in case someone else has same problem

    it('should retry and return access token', async () => {
        const response: AxiosResponse = {
            data: {
                access_token: 'token1'
            },
            status: 200,
            statusText: 'OK',
            headers: {},
            config: {}
        };

        const err: AxiosError = {
            config: {},
            code: '500',
            name: '',
            message: '',
            response: {
                data: {},
                status: 500,
                statusText: '',
                headers: {},
                config: {}
            },
            isAxiosError: true,
            toJSON: () => null
        };

        let retried = 0;

        const post = jest
            .spyOn(httpService, 'post')
            .mockImplementationOnce(() => {
                return new Observable((s) => {
                    if (retried <= 1) {
                        retried += 1;
                        s.error(err);
                    } else {
                        s.next(response);
                        s.complete()
                    }
                });
            });

        try {
            const token = await service.getAccessToken().toPromise();
            expect(token).toBe('token1');
        } catch (err) {
            expect(true).toBeFalsy();
        }

        expect(post).toHaveBeenCalled();
        expect(post).toHaveBeenCalledTimes(1);
    });

Upvotes: 1

Related Questions