如何在Jest中使用axios测试async redux action

zzzyeukh  于 2023-04-18  发布在  Jest
关注(0)|答案(1)|浏览(131)

我尝试测试async redux actions,下面的函数尝试获取API,因此响应成功,它返回successful_action,否则返回failure_action:

const login = (email, password) => {
  return {
    type: LOGIN,
    user: { email, password },
  }
};

const loginSuccess = () => {
  return {
    type: LOGIN_SUCCESS
  }
}

const loginFailure = () => {
  return {
    type: LOGIN_FAILURE
  }
}

const reducers = (state={}, action) => {
  switch(action.type) {
    case LOGIN:
      return {...state, ...action};
    case LOGIN_SUCCESS:
      return {...state, LOGIN_SUCCESS};
    case LOGIN_FAILURE:
      return {...state, LOGIN_FAILURE};
    default:
      return state;
  }
}

const someFn = (email, password) => (dispatch) => {
  dispatch(login(email, password))
  axios.get(some API)
    .then( response => dispatch(loginSuccess()))
    .catch( error => dispatch(loginFailure()))
};

上面的函数应该返回(在两种情况下):

// in success case
{
  type: 'LOGIN',
  user: { email: 'test@test', password: 123 },
  LOGIN_FAILURE: 'LOGIN_FAILURE'
},
// in failure case
{
  type: 'LOGIN',
  user: { email: 'test@test', password: 123 },
  LOGIN_SUCCESS: 'LOGIN_SUCCESS'
}

我尝试了不同的方法,但我总是得到'undefined'作为输出,并显示错误消息:
TypeError:无法读取undefined的属性(阅读'then')
我的测试用例:

const middleware = [thunk];
const mockStore = configureStore(middleware);
const mock = new MockAdapter(axios);
const store = mockStore({});

it('TEST CASE 5', () => {
    mock.onGet("...someapi").reply(200, 
      {
        ...some payload
      }
    );

    const expectedActions = [
      {
        type: 'LOGIN',
        user: { email: 'test@test', password: 123 },
        LOGIN_FAILURE: 'LOGIN_FAILURE'
      },
      {
        type: 'LOGIN',
        user: { email: 'test@test', password: 123 },
        LOGIN_SUCCESS: 'LOGIN_SUCCESS'
      }
    ]

    return store.dispatch(someFn("test@test", 123)).then(() => {
      expect(response).toEqual(expectedActions)
    })
  })

我试图在StackOverflow上导航抛出其他类似的问题,但没有一个对我有帮助

yyhrrdl8

yyhrrdl81#

1.您忘记在someFn形实转换中返回axios.get()
1.每个测试用例都应该测试一种情况。您的示例中有两种情况:登录成功和登录失败。因此,我们应该将它们分为两个测试用例。
我可以看到你正在使用redux-mock-store,请注意:
请注意,这个库是用来测试动作相关的逻辑,而不是reducer相关的逻辑。换句话说,它不会更新Redux商店。
例如:
thunk.ts

import axios from 'axios';

const login = (email, password) => {
  return {
    type: 'LOGIN',
    user: { email, password },
  };
};

const loginSuccess = (user) => {
  return {
    type: 'LOGIN_SUCCESS',
    user,
  };
};

const loginFailure = (error) => {
  return {
    type: 'LOGIN_FAILURE',
    user: null,
    error,
  };
};

export const someFn = (email, password) => (dispatch) => {
  dispatch(login(email, password));
  return axios
    .get('/user', { params: { email, password } })
    .then((response) => dispatch(loginSuccess(response.data)))
    .catch((error) => dispatch(loginFailure(error.message)));
};

thunk.test.ts

import configureStore from 'redux-mock-store';
import thunk, { ThunkDispatch } from 'redux-thunk';
import MockAdapter from 'axios-mock-adapter';
import axios from 'axios';

import { someFn } from './thunk';
import { AnyAction } from 'redux';

export type RootState = any;
type DispatchExts = ThunkDispatch<RootState, undefined, AnyAction>;

const middleware = [thunk];
const mockStore = configureStore<RootState, DispatchExts>(middleware);
const mock = new MockAdapter(axios);
const store = mockStore({});

beforeEach(() => {
  store.clearActions();
});
it('should login success', () => {
  const email = 'test@test';
  const password = 123;
  mock.onGet('/user', { params: { email, password } }).reply(200, {
    id: 1,
    email,
    password,
  });

  const expectedActions = [
    { type: 'LOGIN', user: { email, password } },
    { type: 'LOGIN_SUCCESS', user: { id: 1, email, password } },
  ];

  return store.dispatch(someFn(email, password)).then(() => {
    expect(store.getActions()).toEqual(expectedActions);
  });
});

test('should login failure', () => {
  const email = 'test@test';
  const password = 123;
  mock.onGet('/user', { params: { email, password } }).networkError();

  const expectedActions = [
    { type: 'LOGIN', user: { email, password } },
    { type: 'LOGIN_FAILURE', user: null, error: 'Network Error' },
  ];

  return store.dispatch(someFn(email, password)).then(() => {
    expect(store.getActions()).toEqual(expectedActions);
  });
});

测试结果:

PASS  stackoverflow/75992743/thunk.test.ts (8.96 s)
  ✓ should login success (4 ms)
  ✓ should login failure (1 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |                   
 thunk.ts |     100 |      100 |     100 |     100 |                   
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        9.603 s

相关问题