如何使用Redux Saga测试API请求失败?

Lud*_*udo 27 javascript generator reactjs redux redux-saga

我试图测试我的传奇可以遵循的每个场景,但我无法实现我想要的行为.这很简单,我有一个HTTP请求(登录),我想通过模拟我的API方法来测试成功和失败的情况.

但是,它看起来call effect不会激活我的api功能,我还没有真正得到它是​​如何工作的,但我想中间件是负责调用该功能,因为我不去通过商店我的测试,我无法得到结果.

所以我的问题是,当您需要在异步调用旁边发送不同的操作(通常是成功或失败)时,如何测试您的传奇?

我找了一个例子,我发现sagas成功并失败但是失败案例从未经过测试,例如在这里的购物车示例中

SAGA.JS

export function* login(action) {
  try {
    const user = yield call(api.login, action);
    return yield put(actions.loginSuccess(user));
  } catch(e) {
    yield put(actions.loginFail(e));
  }
}

export default function* rootAuthenticationSagas() {
  yield* takeLatest(LOGIN, login);
}
Run Code Online (Sandbox Code Playgroud)

TEST.JS

describe('login', () => {
  context('When it fails', () => {
    before('Stub the api', () => {
      sinon.stub(api, 'login', () => {
        // IT NEVER COMES HERE !
        return Promise.reject({ error: 'user not found' });
      });
    });

    it('should return a LOGIN_FAIL action', () => {
      const action = {
        payload: {
          name: 'toto',
          password: '123456'
        }
      };
      const generator = login(action);

      // THE CALL YIELD
      generator.next();

      const expectedResult = put({ type: 'LOGIN_FAIL', payload: { error: 'user not found' } });
      expect(generator.next().value).to.be.eql(expectedResult); // FAIL BECAUSE I GET A LOGIN_SUCCESS INSTEAD OF A FAIL ONE
    });
  });
});
Run Code Online (Sandbox Code Playgroud)

Dan*_*mov 43

马克的答案是对的.中间件执行这些指令.但是这会让你的生活变得更轻松:在测试中,你可以提供你想要的任何东西作为参数next(),并且生成器函数将接收它作为结果yield.这正是saga中间件的作用(除了它实际上是激发请求而不是给你一个假响应).

yield获取任意值,请将其传递给next().要使其"接收"错误,请将其传递给throw().在你的例子中:

it('should return a LOGIN_FAIL action', () => {
  const action = {
    payload: {
      name: 'toto',
      password: '123456'
    }
  };
  const generator = login(action);

  // Check that Saga asks to call the API
  expect(
    generator.next().value
  ).to.be.eql(
    call(api.login, action)
  );

  // Note that *no actual request was made*!
  // We are just checking that the sequence of effects matches our expectations.

  // Check that Saga reacts correctly to the failure
  expect(
    generator.throw({
      error: 'user not found'
    }).value
  ).to.be.eql(
    put({
      type: 'LOGIN_FAIL',
      payload: { error: 'user not found' }
    })
  );
});
Run Code Online (Sandbox Code Playgroud)


mar*_*son 9

正确 - 据我所知,Redux-Saga的重点在于你的saga函数使用saga API返回描述操作的对象,然后中间件会查看这些对象以实际执行该行为.因此,yield call(myApiFunction, "/someEndpoint", arg1, arg2)传奇中的语句可能会返回一个概念性的对象{effectType : CALL, function: myApiFunction, params: [arg1, arg2]}.

您可以检查redux-saga源以查看这些声明性对象的确切外观,并在测试中创建匹配对象以进行比较,或者使用API​​函数本身来创建对象(我认为redux-saga是什么)在他们的测试代码中).