簡體   English   中英

如何使用jest在redux中模擬異步動作創建者

[英]How to mock an async action creator in redux with jest

我正在嘗試使用jest為redux異步動作創建器編寫單元測試。

asyncActions.js:

const startSignInRequest = () => ({
  type: START_SIGNIN_REQUEST
});

// action creator to dispatch the success of sign In
export const signInSucceded = user => ({
  type: SIGNIN_USER_SUCCEEDED,
  user
});

// action creator to dispatch the failure of the signIn request
export const signInFailed = error => ({
  type: SIGNIN_USER_FAILED,
  error
});

const signInUser = user => dispatch => {
dispatch(startSignInRequest);
  return signInApi(user).then(
    response => {
      const { username, token } = response.data;
      dispatch(signInSucceded(username));
      localStorage.setItem("token", token);
      history.push("/homepage");
    },
    error => {
      let errorMessage = "Internal Server Error";
      if (error.response) {
        errorMessage = error.response.data;
      }
      dispatch(signInFailed(errorMessage));
      dispatch(errorAlert(errorMessage));
    }
  );
};

signInApi.js:

import axios from "axios";
import { url } from "../../env/config";

const signInApi = async user => {
  const fetchedUser = await axios.post(`${url}/signIn`, {
    email: user.email,
    password: user.password
  });
  return fetchedUser;
};

在redux官方文檔的Writing測試中,他們使用fetch-mock庫。 但是,我認為這個庫叫真正的Api。 我試圖用jest mocks模擬嘲笑axios api。

/__mocks/signInApi.js:

const users = [
{
    login: 'user 1',
    password: 'password'
}
];

  export default function signInApi(user) {
    return new Promise((resolve, reject) => {
      const userFound = users.find(u => u.login === user.login);
      process.nextTick(() =>
        userFound
          ? resolve(userFound)
          // eslint-disable-next-line prefer-promise-reject-errors
          : reject({
              error: 'Invalid user credentials',
            }),
      );
    });
  }

__tests / asyncActions.js:

jest.mock('../axiosApis/signInApi');
import * as actions from '../actions/asyncActions';

describe('Async action creators', async () => {
it('Should create SIGN_IN_USER_SUCCEEDED when signIn user has been done', () => {
    const user = {
                    login: 'user 1',
                    password: 'password'
                }
    await expect(actions.signInUser(user)).resolves.toEqual({
        user
    })
})
});

測試失敗了,我得到了:

expect(received).resolves.toEqual()

Matcher error: received value must be a promise

Received has type:  function
Received has value: [Function anonymous]

如何只用jest模擬這個異步動作創建者?

編輯:我必須編輯我的答案,因為第一個指向錯誤的方向。

所以根據我的理解,你想要模擬Action + Return值。 在你的情況下,我會立即返回你的模擬函數的結果。 因為你沒有嘲笑axios.post你不需要將所有內容包裝在一個promise中並返回它。 你不是只嘲笑HTTP調用而是嘲笑整個行動。

const users = [
{
    login: 'user 1',
    password: 'password'
}
];

  export default function signInApi(user) {
    const userFound = users.find(u => u.login === user.login);
    return (userFound ? userFound : {
      error: 'Invalid user'
    });
  }

看起來您需要更新您的模擬以解析為這樣的對象:

export default function signInApi(user) {
  return new Promise((resolve, reject) => {
    const userFound = users.find(u => u.login === user.login);
    process.nextTick(() =>
      userFound
        ? resolve({  // <= resolve to an object
          data: {
            username: 'the username',
            token: 'the token'
          }
        })
        // eslint-disable-next-line prefer-promise-reject-errors
        : reject({
          error: 'Invalid user credentials',
        }),
    );
  });
}

...那么你真正測試的是actions.signInUser返回一個可以用user調用的函數 ...

...然后返回另一個函數 ,該函數可以使用dispatch來調用,該dispatch調度正確的操作:

jest.mock('./signInApi');
import * as actions from './asyncActions';

describe('Async action creators', () => {
  it('Should create SIGN_IN_USER_SUCCEEDED when signIn user has been done', async () => {
    const user = {
      login: 'user 1',
      password: 'password'
    };
    const dispatch = jest.fn();
    await actions.signInUser(user)(dispatch);  // <= call the function on a user, then call the resulting function on a dispatch
    expect(dispatch).toHaveBeenCalledTimes(2);  // Success!
    expect(dispatch).toHaveBeenNthCalledWith(1, { type: START_SIGNIN_REQUEST });  // Success!
    expect(dispatch).toHaveBeenNthCalledWith(2, { type: SIGNIN_USER_SUCCEEDED, user: 'the username' });  // Success!
  })
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM