【问题标题】:Jest with Enzyme, why is `toHaveBeenCalled` not triggering in my React Component test?开酶玩笑,为什么在我的 React 组件测试中没有触发 `toHaveBeenCalled`?
【发布时间】:2020-05-21 12:32:17
【问题描述】:

我正在 React 应用程序中进行单元测试,以验证传入的 prop 函数是否根据另一个 props 值有条件地调用。我在我的应用程序中使用 Typescript/Enzyme/Jest,并在我正在测试的组件周围使用 Root 包装器来注入 Redux 存储(并在需要时覆盖初始状态)。

import { mount, ReactWrapper } from "enzyme";
import React from "react";
import Login from "src/components/auth/Login";
import Root from "src/Root";

let wrapped: ReactWrapper;

let defaultProps = {
  signIn: jest.fn(),
  token: null,
};

beforeEach(() => {
  wrapped = mount(
    <Root>
      <Login {...defaultProps} />
    </Root>
  );
});

describe("on mount", () => {
  describe("if no token is supplied to the props", () => {
    it("will call the props.signIn() function", () => {
      expect(defaultProps.signIn).toHaveBeenCalled();
    });
  });
});

当我运行测试时,toHaveBeenCalled()(以及toBeCalled(),都尝试过)没有注册任何调用。但是,我提供了一个 console.log 语句,该语句在与 signIn() 函数存在的相同条件下被触发。

import React from 'react';
import { AuthState, JWT } from "src/components/auth/types";
import { signIn } from "src/redux/auth";

interface Props {
  signIn: () => Promise<void>;
  token: null | JWT;
}

class Login extends React.Component<Props> {
  /**
   * Sign the user in on mount
   */
  public componentDidMount(): void {
    if (!this.props.token) {
      console.log("GETTING HERE");
      this.props.signIn();
    }
  }

  public render(): JSX.Elemeent {
    // ... More code
  }
}

const mapStateToProps = (state: AuthState) => {
  return {
    token: state.auth.token;
  };
};

export default connect(mapStateToProps, { signIn })(Login);

我浏览了几篇相关的帖子/文章,但所有不同的配置,例如遍历酶以获得直接道具或利用spyOn,都失败了。

我能想到的唯一不同之处是我用Root 包装了Login 组件,但考虑到我可以看到console.log 被触发,这似乎完全是在黑暗中拍摄。

谁能告诉我我在这里做错了什么?

【问题讨论】:

    标签: reactjs typescript testing jestjs enzyme


    【解决方案1】:

    你必须等待组件挂载,所以:

    it("will call the props.signIn() function", (done) => {
      setImmediate(() => {
        expect(defaultProps.signIn).toHaveBeenCalled();
        done()
      });
    });
    

    【讨论】:

    • 当您在全球范围内声明 signIn: jest.fn(), 时,您可能无法获得准确的结果。您可能想在 beforeEach 中更改它的引用。
    • 感谢您的回复,很遗憾这没有奏效。它仍然会在没有触发呼叫的情况下返回。并感谢您对 beforeEach 的建议。
    • 您的项目中是否大量使用酶?它没有提供任何钩子来解决这个问题。如果您可以使用@testing-library/react,那就更好了。
    • 你能试试浅包装吗?还有你的根组件是做什么的?
    • 问题实际上出在商店上。我将不得不更新问题并添加答案。感谢您的帮助。
    【解决方案2】:

    最后是我忘记通过mapDispatchToPropsmapStateToPropsconnect 函数中放置覆盖。这导致我传入的signIn 函数被文件中导入的signIn 操作覆盖。使用 ownProps 更新并有条件地使用传入的值可以解决问题:

    const mapStateToProps = (state: AuthState, ownProps: Props) => {
      return {
        token: ownProps.token || state.auth.token;
      };
    };
    
    const mapDispatchToProps = (dispatch: ThunkDispatch<{}, {}, any>, ownProps: Props) => {
      return {
        signIn: ownProps.signIn || (() => { return dispatch(signIn()) })
      }
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Login);
    

    【讨论】:

      猜你喜欢
      • 2019-05-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-09
      • 2020-03-17
      • 2017-07-13
      • 1970-01-01
      • 2018-03-31
      • 1970-01-01
      相关资源
      最近更新 更多