#Help test observable with marble strings

6 messages · Page 1 of 1 (latest)

rough apex
#

Hey, I'm new to writing tests for RxJS and am really struggling. I was hoping for help writing a unit test, but more specifically on how to write a marble string (I'm really not understanding how to handle the retry delay). I've distilled my code down to the following function:

renewToken$(): Observable<OAuthToken> {
  return this.http.post<OAuthToken>(this._endpoint, this._credentials).pipe(
    retry({
      count: 2,
      delay: 3000,
      resetOnSuccess: true,
    }),
    map((response) => this.parseToken(response)),
    tap((token) => this.validateToken(token)),
    switchMap((token) => this.receiveToken(token)),
  );
}

I'm testing some error handling for 4XX responses. In this case I expect 3 post requests are made total. When the last retry fails, I expect that the error will fall through. Please, could a kind someone show me an example for this?

sharp field
#

Do you want to test this method returns or test rxjs operators and streams more precisely ?

#

If you want just to test this method consider use spyobj

rough apex
#

Well, in actual use I expect that my post request will end up getting rate limited. I wrote some error handling for HTTP 429 responses that is getting handled within the retry delay argument (I just put it as 3000 for demo purposes). Because this is used to get an Auth token to use with other API calls, it's pretty essential that I get this function correct. So to answer you question, I'd like to test this as precisely as possible.

Here's my incomplete test so far:

it("should retry maxRetries times when failed", () => {
  const delay = service.retryDelayMs;
  const retries = service.maxRetries;
  const totalDelay = delay * retries;

  const errorStub = {
    message: "Request failed with status code 4XX",
    code: AxiosError.ERR_BAD_REQUEST,
    config: undefined,
    request: undefined,
    response: {
      status: HttpStatus.BAD_REQUEST,
      statusText: "BAD REQUEST",
      headers: {},
      config: {} as any,
      data: {},
    },
  };

  scheduler.run((helpers) => {
    const { cold } = helpers;
    const coldPost$ = cold(" #", undefined, errorStub);
    http.post.mockImplementation(() => coldPost$);
    const source = service.renewToken$();
    const expectedMarbles = ` ${totalDelay}ms #`;
    helpers
      .expectObservable(source)
      .toBe(expectedMarbles, undefined, errorStub);
  });
});

The test is currently passing, but again, it's incomplete (I'm not even sure if it's correct to be entirely honest). It's not yet testing that the request is attempted n times total. When I put a spy on http.post, the spy was only being called 1 time, but the subscription is definitely happening 3 times. I am a little confused, because I had thought that when retry resubscribed it should be calling http.post again, right? So really what I want is to test that http.post is being subscribed to n times, and / or invoked n times.

rough apex
#

I'm starting to wonder if I have a fundamental misunderstanding. Is the retry operator going to retry the actual request (which is what I want)? Or, is it trying to reprocess the initial response returned by the request?

dense musk
#

Please, do not crosspost.
I replied to you in #rxjs.