首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为使用RxJS运算符的retryWhen编写测试(理解与重试操作符的区别)

为使用RxJS运算符的retryWhen编写测试(理解与重试操作符的区别)
EN

Stack Overflow用户
提问于 2020-01-16 13:47:04
回答 1查看 755关注 0票数 1

我试图为以下使用retryWhen运算符的函数编写测试:

代码语言:javascript
复制
// some API I'm using and mocking out in test
import { geoApi } from "api/observable";

export default function retryEpic(actions$) {
  return actions$.pipe(
    filter(action => action === 'A'),
    switchMap(action => {
      return of(action).pipe(
        mergeMap(() => geoApi.ipLocation$()),
        map(data => ({ data })),
        retryWhen(errors => {
          return errors.pipe(take(2));
        }),
      );
    }),
  );
}

代码应该执行对某个远程API geoApi.ipLocation$()的请求。如果遇到错误,则在放弃之前重试两次。

我编写了以下使用Jest和RxJS TestScheduler的测试代码:

代码语言:javascript
复制
function basicTestScheduler() {
  return new TestScheduler((actual, expected) => {
    expect(actual).toEqual(expected);
  });
}

const mockApi = jest.fn();
jest.mock('api/observable', () => {
  return {
    geoApi: {
      ipLocation$: (...args) => mockApi(...args),
    },
  };
});

describe('retryEpic()', () => {
  it('retries fetching 2 times before succeeding', () => {
    basicTestScheduler().run(({ hot, cold, expectObservable, expectSubscriptions }) => {
      const actions$ = hot('-A');

      // The first two requests fail, third one succeeds
      const stream1 = cold('-#', {}, new Error('Network fail'));
      const stream2 = cold('-#', {}, new Error('Network fail'));
      const stream3 = cold('-r', { r: 123 });

      mockApi.mockImplementationOnce(() => stream1);
      mockApi.mockImplementationOnce(() => stream2);
      mockApi.mockImplementationOnce(() => stream3);

      expectObservable(retryEpic(actions$)).toBe('----S', {
        S: { data: 123 },
      });

      expectSubscriptions(stream1.subscriptions).toBe('-^!');
      expectSubscriptions(stream2.subscriptions).toBe('--^!');
      expectSubscriptions(stream3.subscriptions).toBe('---^');
    });
  });
});

这个测试失败了。

但是,当我将retryWhen(...)替换为简单的retry(2)时,测试就成功了。

看来我不太明白如何用retry实现retryWhen。我怀疑这个take(2)正在关闭流,并且某种程度上阻止了一切的继续。但我不太明白。

实际上,我想在retryWhen()中编写一些附加逻辑,但首先,我需要了解如何使用retryWhen()正确地实现retry()。或者这实际上是不可能的?

其他资源

我的retryWhen + take是基于这个实现的,所以答案是:

官方文件:

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-20 11:20:51

您可以将retryWhen用于这两个目的,第一个目的是在其中包含您的逻辑,第二个目的是您希望给它的重试编号(不需要使用retry操作符):

代码语言:javascript
复制
// some API I'm using and mocking out in test
import { geoApi } from "api/observable";

export default function retryEpic(actions$) {
  return actions$.pipe(
    filter(action => action === 'A'),
    switchMap(action => {
      return of(action).pipe(
        mergeMap(() => geoApi.ipLocation$()),
        map(data => ({ data })),
        retryWhen(errors =>
          errors.pipe(
            mergeMap((error, i) => {
              if (i === 2) {
                throw Error();
              }
              // return your condition code
            })
          )
        )
      )
    }),
  );
}

这是一个简单的演示

至于理解这一逻辑:

根据您引用的官方文档,retryWhenretry操作符:

重新订阅可观察到的源(如果没有错误或完成执行)

这就是为什么不能将retryretryWhen连接在一起的原因。你可以说这些操作人员是断链器..。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59771033

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档