如何测试使用酶更改 useState 状态的点击事件?

How can I test a click event which changes a useState state with enzyme?

我有以下组件:

import React, { useState } from "react";

import { Button, ThirteenBold } from "@selfdecode/sd-component-library";
import { PlayIcon } from "assets/icons";
import { TourButtonProps } from "./interfaces";
import { WelcomeVideoModal } from "../../modals/welcome-video-modal";

/**
 * The tour button.
 */
export const TourButton: React.FC<TourButtonProps> = (props) => {
  const [isIntroVideoShowing, setIsIntroVideoShowing] = useState(false);

  return (
    <>
      <WelcomeVideoModal
        isOpen={isIntroVideoShowing}
        onClickX={() => setIsIntroVideoShowing(false)}
        data-test="tour-button-welcome-video"
      />

      <Button
        {...props}
        width={["max-content"]}
        variant="tour"
        onClick={() => setIsIntroVideoShowing(true)}
        data-test="tour-button"
      >
        <ThirteenBold
          mr={["12px"]}
          color="cl_blue"
          width={["max-content"]}
          letterSpacing={["1px"]}
          display={["none", "block"]}
          textTransform="uppercase"
        >
          welcome tour
        </ThirteenBold>

        <PlayIcon style={{ height: "30px", fill: "#4568F9" }} />
      </Button>
    </>
  );
};

并且测试覆盖率报告抱怨我没有测试两个 onClick 事件,这会改变状态。

我尝试了两种方法,但都失败了。 方法一是模拟 useState 并查看它是否像我预期的那样被调用。 这是我试过的测试:

 const setState = jest.fn();
 const useStateMock: any = (initState: any) => [initState, setState];
 jest.spyOn(React, "useState").mockImplementation(useStateMock);
 
 const button = wrapper.find(`[data-test="tour-button"]`);
 expect(button).toHaveLength(1);
 button.simulate("click");
 expect(setState).toHaveBeenCalled();

这甚至不应该是最终测试,因为它不检查调用它的值是什么,但它仍然失败了,因为甚至没有调用 useState。

我尝试的第二种方法是检查此组件上的道具值:

 <WelcomeVideoModal
    isOpen={isIntroVideoShowing}
    onClickX={() => setIsIntroVideoShowing(false)}
    data-test="tour-button-welcome-video"
 />

这是我试过的测试

  test("Check the isIntroVideoShowing changes to true on buton click", () => {
    jest.spyOn(React, "useState").mockImplementation(useStateMock);
    const button = wrapper.find(`[data-test="tour-button"]`);
    const welcomeVideo = wrapper.find(
      `[data-test="tour-button-welcome-video"]`
    );
    expect(button).toHaveLength(1);
    expect(welcomeVideo.prop("isOpen")).toEqual(false);
    button.simulate("click");
    expect(welcomeVideo.prop("isOpen")).toEqual(true);
  });

即使在点击之后,这个也失败了,声称它是用 false 调用的。

有没有办法让这些工作?或者用不同的方法来覆盖这些?

您需要提供 wrapper.update 以在模拟点击事件后使用状态更改更新模板。

test("Check the isIntroVideoShowing changes to true on buton click", () => {
    jest.spyOn(React, "useState").mockImplementation(useStateMock);
    const button = wrapper.find(`[data-test="tour-button"]`);
    const welcomeVideo = wrapper.find(
      `[data-test="tour-button-welcome-video"]`
    );
    expect(button).toHaveLength(1);
    expect(welcomeVideo.prop("isOpen")).toEqual(false);
    button.simulate("click");
    wrapper.update();
    expect(welcomeVideo.prop("isOpen")).toEqual(true);
  });

参考 - https://enzymejs.github.io/enzyme/docs/api/ShallowWrapper/update.html