如何使用Redux Saga测试API请求失败? [英] How to test API request failures with Redux Saga?

查看:118
本文介绍了如何使用Redux Saga测试API请求失败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to test every scenarios my saga could follow, but i am not able to make happens the behaviors i want. This is pretty simple, i have a HTTP request (login), and i want to test the success and the failure cases by mocking my API method.

但是,看起来调用效果不会触发我的api函数,我还没有真正了解它是如何工作的,但我想中间件是负责的调用该函数,因为我不通过我的测试商店,我无法得到结果。

But, it looks like the call effect doesn't fire my api function, i don't really get yet how it works, but i guess that the middleware is in charge of invoking the function, and since i don't go though the store on my test, i can't get the result.

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

So my question is, how can you test your saga when you need to dispatch different actions (typically success or failure) next to your async call ?

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

I looked for an example, i found sagas with success and fail but the fail case is never tested, for example in the shopping cart example here

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);
}

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
    });
  });
});


推荐答案

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

Mark’s answer is correct. Middleware executes those instructions. But this makes your life easier: in the test, you can provide whatever you want as the argument to next(), and the generator function will receive it as a result of yield. This is exactly what saga middleware does (except that it actually fires up a request instead of giving you a fake response).

使 yield 获取一个任意值,将其传递给 next()。要使其接收错误,请将其传递给 throw()。在您的示例中:

To make yield get an arbitrary value, pass it to next(). To make it "receive" an error, pass it to throw(). In your example:

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' }
    })
  );
});

这篇关于如何使用Redux Saga测试API请求失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆