首页 > 解决方案 > 开玩笑异步操作创建者:TypeError:无法读取未定义的属性“then”

问题描述

有点新手在这里开玩笑。我正在尝试使用 jest 为我的 React 项目中的异步操作创建者之一编写单元测试用例。我一直遇到错误TypeError: Cannot read property 'then' of undefined

下面是我的动作创建者:

import {loginService} from "./services";

export function login(email: string, password: string): (dispatch: ThunkDispatch<{}, {}, any>) => void {
  return dispatch => {
    dispatch(loggingIn(true));
    loginService(email, password).then(
      (response: any) => {
        dispatch(loggingIn(false));
        dispatch(loginAction(response));
      },
      error => {
       //Code
        }
        dispatch(loggingIn(false));
        dispatch(loginError(true, message));
      }
    );
  };
}

./services.js

export const loginService = (username: string, password: string) => {
  const requestOptions = {
    method: "POST",
    headers: {
      //Headers
    },
    body: JSON.stringify({email: username, password: password})
  };
  return fetch(`url`, requestOptions)
    .then(handleResponse, handleError)
    .then((user: any) => {
      //code
      return user;
    });
};

下面是我的测试:

it("login", () => {
    fetchMock
      .postOnce("/users/auth", {
        body: JSON.parse('{"email": "user", "password": "password"}'),
        headers: {"content-type": "application/json"}
      })
      .catch(() => {});
    const loginPayload = {email: "user", password: "password"};
    const expectedSuccessActions = [
      {type: types.LOGGING_IN, payload: true},
      {type: types.LOGIN, loginPayload}
    ];
    const expectedFailureActions = [
      {type: types.LOGGING_IN, payload: true},
      {type: types.LOGIN_ERROR, payload: {val: true, errorMessage: "error"}}
    ];
    const store = mockStore({user: {}});
    const loginService = jest.fn();
    return store.dispatch(LoginActions.login("email", "password")).then(() => {
      expect(store.getActions()).toEqual(expectedSuccessActions);
    });
  });

请帮忙

标签: reactjsjestjsenzymeredux-async-actions

解决方案


调度您的LoginActions.login()操作返回的最终结果是void(或undefined)。不是 a Promise,所以不是你可以.then()在测试中调用的东西。

从您的测试代码来看,您正在fetch-mock使用fetchMock. 您应该能够等待该操作完成,然后再测试商店是否发送了正确的操作:

it("login", async () => {
//          ^^^^^ --> note that you need to make your test async to use await

    store.dispatch(LoginActions.login("email", "password"));
    await fetchMock.flush();

    expect(store.getActions()).toEqual(expectedSuccessActions);
});

请注意,您的代码中的注释似乎表明您loginService在从.then()回调返回之前做了更多的事情。如果这需要太长时间,等待fetchMock完成可能不会等待足够长的时间。在这种情况下,您应该考虑Promise从您的LoginActions.login()操作中返回,以便您可以测试它。您是否应该取决于调整您的应用程序以处理该问题需要付出多少努力,因为您不希望您的应用程序在登录失败的情况下因任何未处理的承诺拒绝错误而崩溃。


推荐阅读