首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >当使用React和jest将状态挂钩传递给子组件时,如何测试副作用?

当使用React和jest将状态挂钩传递给子组件时,如何测试副作用?
EN

Stack Overflow用户
提问于 2021-04-19 03:33:05
回答 1查看 988关注 0票数 1

我想测试一个子组件,但是它依赖于父组件的状态(钩子)。

子节点接收isModalOpensetIsModalOpen作为属性。每次isModalOpen发生变化时,Child内部的useEffect都会触发。但是,当我试图单独测试Child组件时,我无法强制状态更改触发useEffect挂钩。我如何实现这一点而不必在测试环境中呈现Parent

在下面的示例中,我可以通过呈现Parent来通过测试。我只想渲染Child,并且仍然通过测试。

代码语言:javascript
运行
复制
function Child({ isModalOpen, setIsModalOpen }) {
  useEffect(() => {
    console.log("is the modal open?", isModalOpen);
  }, [isModalOpen]);

  return (
    <button data-testId="myBtn" onClick={() => setIsModalOpen(!isModalOpen)}>
      Click to {isModalOpen ? "close" : "open"} modal
    </button>
  );
}

function Parent() {
    const [isModalOpen, setIsModalOpen] = useState(false);
    return <Child isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} />;
}

测试:

代码语言:javascript
运行
复制
it("React test", () => {
  let isModalOpen = false;
  const mockFunction = jest.fn((val) => (isModalOpen = val));

  const { queryByTestId } = render(
    <Child isModalOpen={isModalOpen} setIsModalOpen={mockFunction} />
  );

  const btnEl = queryByTestId("myBtn");

  btnEl.click();
  expect(btnEl.innerHTML).toEqual("Click to close modal");

  // -----
  // -----
  // -----
  // ----- The below code works
  // const { queryByTestId } = render(<Parent />);

  // const btnEl = queryByTestId("myBtn");

  // btnEl.click();
  // expect(btnEl.innerHTML).toEqual("Click to close modal");
});

下面是上面代码片段的一个工作示例:https://codesandbox.io/s/jest-test-forked-cjm3r?file=/index.test.js

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-04-19 03:52:37

实际上,总结一下,如果将钩子传递给孩子,那么您要测试的内容与钩子无关。把孩子想象成被测试的subject;换句话说,它是您唯一想要测试的东西。顾名思义,“钩子”是无关紧要的。传入一个函数,就可以断言调用了一个具有适当值的函数。

总之,你有两个案子

  1. 打开并单击“单击关闭模态”按钮时,该模式将关闭或以其他方式已知正在以false调用模拟函数。当该模式关闭时,单击“单击关闭模态”按钮,该模式将打开或以其他已知的方式使用true调用模拟函数。

为了演示这一点,我对上面的测试做了一些小编辑。请随意复制和粘贴它,并为自己检查,并让我知道,如果你有问题。

注意:从沙箱链接中复制和粘贴,只需稍作修改,以避免与原始代码产生太大差异。

代码语言:javascript
运行
复制
it("closes the modal when clicking on the button", () => {
    function Child({ isModalOpen, setIsModalOpen }) {
        useEffect(() => {
            console.log("is the modal open?", isModalOpen);
        }, [isModalOpen]);

        return (
            <button data-testId="myBtn" onClick={() => setIsModalOpen(!isModalOpen)}>
                Click to {isModalOpen ? "close" : "open"} modal
            </button>
        );
    }

    // notice the mock here doesn't take arguments
    const mockFunction = jest.fn();

    const { queryByTestId } = render(
        // notice that I've set the initial value for isModal to true
        <Child isModalOpen={true} setIsModalOpen={mockFunction} />
    );

    const btnEl = queryByTestId("myBtn");

    btnEl.click();
    expect(btnEl.innerHTML).toEqual("Click to close modal");

    // the assertion here
    expect(mockFunction).toHaveBeenCalledWith(false);
});

it("opens the modal when clicking on the bottom", () => {
    function Child({ isModalOpen, setIsModalOpen }) {
        useEffect(() => {
            console.log("is the modal open?", isModalOpen);
        }, [isModalOpen]);

        return (
            <button data-testId="myBtn" onClick={() => setIsModalOpen(!isModalOpen)}>
                Click to {isModalOpen ? "close" : "open"} modal
            </button>
        );
    }

    const mockFunction = jest.fn();

    const { queryByTestId } = render(
        // notice that I've set the initial value for isModal to false
        <Child isModalOpen={false} setIsModalOpen={mockFunction} />
    );

    const btnEl = queryByTestId("myBtn");

    btnEl.click();
    expect(btnEl.innerHTML).toEqual("Click to open modal");

    // the assertion here
    expect(mockFunction).toHaveBeenCalledWith(true);
});
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67155636

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档