unit-testing - RxJS Redux-Observables 测试 retryWhen inside an epic

标签 unit-testing rxjs rxjs5 redux-observable

我正在努力研究如何在 redux-observable epic 中测试 retryWhen 运算符。基于this example取自 docs ,我 fork 了this jsbin我正在尝试测试响应失败 2 次并在之后返回有效响应的情况。

下面是部分代码。对于整个实现,请使用 this jsbin

let RetryStrategy = attempts => attempts
    .zip(Observable.range(1, 4))
    .flatMap(([error, i]) => {
        if (i > 3) {
            return Observable.throw('Network error occured')
        }
        return Observable.timer(i * 1000)
    })


const fetchFooEpic = (action$, store, call = indirect.call) =>
    action$.ofType('FETCH_FOO')
        .mergeMap(action =>
            call(api.fetchFoo, action.payload.id)
                .map(payload => ({ type: 'FETCH_FOO_FULFILLED', payload }))
                .retryWhen(RetryStrategy)
                .takeUntil(action$.ofType('FETCH_FOO_CANCELLED'))
                .catch(error => of({
                    type: 'FETCH_FOO_REJECTED',
                    payload: error.xhr.response,
                    error: true
                }))
        );

describe('fetchFooEpic', () => {
    ...
    it.only('handles errors correctly', () => {
        const badResponse = { message: 'BAD STUFF' };
        const response = { id: 123, name: 'Bilbo' };

        expectEpic(fetchFooEpic, {
            expected: ['-----a|', {
                a: { type: 'FETCH_FOO_FULFILLED', payload: response }
            }],
            action: ['(a|)', {
                a: { type: 'FETCH_FOO', payload: { id: 123 } }
            }],
            response: ['-#-#-a|', {
                a: response
            }, { xhr: { badResponse } }],
            callArgs: [api.fetchFoo, 123]
        });
    });
    ...

});

如果您检查 jsbin 中的响应,则实际操作总是在一个数组中。

最佳答案

我有一个类似的问题,我试图测试一个 Angular HttpInterceptor,它最多尝试三次,两次尝试之间有延迟。正如您在评论中提到的, retryWhen 在每次错误后重新订阅可观察对象。这意味着如果您有一个可观察到的错误(例如 cold('#|')),您将始终在 retryWhen 中得到一个错误,因为在每次重试时都会重新订阅相同的可观察到的错误。

这看起来像是 hack,但我创建了这个简单的类,它按照给定的顺序订阅不同的可观察对象。

  class MultiObservable extends Observable<any> {
    constructor(observables: Observable<any>[]) {
      let subscriptionIdx = 0;
      super((subscriber: Subscriber<any>) => 
               observables[subscriptionIdx++].subscribe(subscriber));
    }
  }

在我的测试中,我按如下方式使用它:

  const testObservable = new MultiObservable([
    cold('#|', null, { status: 400 }),
    cold('a|')
  ]);

  next.handle.and.returnValue(testObservable);
  const actual = interceptor.intercept(req, next);
  expect(actual).toBeObservable(cold('---a|'));

我希望其他人会有一个不那么棘手的解决方案,但这现在对我有用。

关于unit-testing - RxJS Redux-Observables 测试 retryWhen inside an epic,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45546750/

相关文章:

java - 如何断言对一个模拟的调用顺序?

c++ - 如何从头开始在 VS 2019 中设置 Google Test?

node.js - TS2585 : 'Promise' only refers to a type, 但在这里用作值

angular - 订阅多个 Observables(比如在 Promises 中链接 then())

php - phpunit 测试的执行顺序是什么?

javascript - 如何使用 jasmine 测试带有 DOM 元素的 JavaScript?

reactjs - React、TypeScript 和 RxJS 测试与 Jest 不工作

angular - 如果 Response 中的状态不是 2XX 系列,angular2 的 http 客户端是否会抛出异常?

Angular 2 RxJS 可观察到的 : RetryWhen filter retry on error Status

angular - RxJS .next() 在 Angular 2 应用程序中默默失败