使用 TestScheduler 测试 Epic 时出现的问题

Issues when testing Epic with TestScheduler

我在 react-redux 应用程序中使用 rxjs 史诗作为异步操作的中间件。

我正在尝试模拟 ajax 请求(通过依赖项注入)并根据响应测试此史诗的行为。

这是我的史诗:

export const loginEpic = (action$, store$, { ajax }) => {         // Ajax method is injected
  return action$.ofType(LoginActions.LOGIN_PENDING).pipe(
    mergeMap(action => {
      if (action.mail.length === 0) {
        return [ loginFailure(-1) ];                              // This action is properly returned while testing
      } else {
        return ajax({ ... }).pipe(
          mergeMap(response => {
            if (response.code !== 0) {
              console.log(response.code);                         // This is logged
              return [ loginFailure(response.code) ];             // This action is expected
            } else {
              return [ loginSuccess() ];
            }
          }),
          catchError(() => {
            return [ loginFailure(-2) ];
          })
        );
      }
    })
  );
};

这部分测试邮件地址是否为空并且工作正常(或者至少符合预期):

  it("empty mail address", () => {
    testScheduler.run(({ hot, expectObservable }) => {
      let action$ = new ActionsObservable(
        hot("a", {
          a: {
            type: LoginActions.LOGIN_PENDING,
            mail: ""
          }
        })
      );

      let output$ = loginEpic(action$, undefined, { ajax: () => ({}) });

      expectObservable(output$).toBe("a", {
        a: {
          type: LoginActions.LOGIN_FAILURE,
          code: -1
        }
      });
    });
  });

但是,我的第二个测试失败了,因为实际值是一个空数组(没有返回登录失败):

  it("wrong credentials", () => {
    testScheduler.run(({ hot, cold, expectObservable }) => {
      let action$ = new ActionsObservable(
        hot("a", {
          a: {
            type: LoginActions.LOGIN_PENDING,
            mail: "foo@bar.com"
          }
        })
      );

      let dependencies = {
        ajax: () =>
          from(
            new Promise(resolve => {
              let response = {
                code: -3
              };
              resolve(response);
            })
          )
      };

      let output$ = loginEpic(action$, undefined, dependencies);

      expectObservable(output$).toBe("a", {
        a: {
          type: LoginActions.LOGIN_FAILURE,
          code: -3
        }
      });
    });
  });

知道我做错了什么/为什么这部分 returns 是一个空数组(console.log 确实记录了代码):

            if (response.code !== 0) {
              console.log(response.code);
              return [ loginFailure(response.code) ];
            }

虽然这部分 returns 是一个填充数组:

      if (action.mail.length === 0) {
        return [ loginFailure(-1) ];
      } 

我猜 Promise 的使用导致测试实际上是异步的。尝试将 ajax 的存根更改为使用 of(response) 而不是 from