如何使用Jest测试检测React组件外部点击

huangapple go评论100阅读模式
英文:

How to test detect click outside a React component with Jest

问题

请参考这里以了解多级菜单渲染的上下文。

我正在尝试测试组件外部点击的检测。到目前为止,我见过的所有示例都与我实现的不同,因此无法正常工作。

请参考这里以获取我到目前为止编写的完整组件。

我迄今为止尝试的测试是:

it("detect click outside", () => {

    const setStateMock = jest.fn();
    const useStateMock: any = (useState: any) => [useState, setStateMock];
    jest.spyOn(React, 'useState').mockImplementation(useStateMock);

    render(<BrowserRouter >
        <MenuItems items={submenusMock} depthLevel={0}/>
    </BrowserRouter>);

    const button = screen.getByTestId("button");

    expect(button).toBeInTheDocument();
    fireEvent.click(button);

    fireEvent.click(document);

    expect(setStateMock).toHaveBeenCalledTimes(1);
});

在这个测试中,我点击一个按钮,让useEffect钩子向文档添加事件监听器,然后点击组件外部。但似乎不起作用。

这里有一个CodeSandbox,测试位于__tests__文件夹中,由于免费版本的CodeSandbox不足以运行测试,因此需要在自己的计算机上运行测试。

英文:

Refer here for context on multilevel menu rendering.

I am trying to test the detection of a click outside the component. All the examples I have seen so far are different than the implementation that I have and thus do not work.

Refer here for the full components I have written so far.

The test I have tried so far is:

it(&quot;detect click outside&quot;, () =&gt; {

    const setStateMock = jest.fn();
    const useStateMock: any = (useState: any) =&gt; [useState, setStateMock];
    jest.spyOn(React, &#39;useState&#39;).mockImplementation(useStateMock);

    render(&lt;BrowserRouter &gt;
        &lt;MenuItems items={submenusMock} depthLevel={0}/&gt;
    &lt;/BrowserRouter&gt;);

    const button = screen.getByTestId(&quot;button&quot;);

    expect(button).toBeInTheDocument();
    fireEvent.click(button);

    fireEvent.click(document);

    expect(setStateMock).toHaveBeenCalledTimes(1);
});

Where I click a button to have the useEffect hook add event listener to the document and then click outside the component. But it does not seem to work.

Here is a codesandbox working. The tests are in the __tests__ folder where the codesandbox is not sufficient enough with a free tier to run the test. So need to run test on own machine.

答案1

得分: 1

你不应该嘲笑useState或其返回值。相反,你应该检查组件的行为是否如预期那样。让我们假设你有一个模态框,在点击按钮时打开并在点击背景时关闭。你的测试可以修改如下:

describe('打开和关闭模态框', () => {
    test('点击按钮时应该打开模态框', () => {
       // 更好地选择用户寻找的内容
       const btn = screen.getByText('打开模态框');
       // 不需要检查是否在文档中,因为如果不在,fireEvent 将引发错误
       fireEvent.click(btn);
       expect(screen.getByTestId('my-modal')).toBeVisible();
    });
    test('点击背景时应该关闭模态框', () => {
       const btn = screen.getByText('打开模态框');
       fireEvent.click(btn);

       fireEvent.click(screen);
       expect(screen.getByTestId('my-modal')).not.toBeVisible();
    });
});

希望对你有帮助。

英文:

You shouldn't ever mock useState or its returns. Instead, you should check to see that your component behaves as expected. Let's imagine that you have a modal that opens on click of a button and closes on click of the background. Your tests could be revised to look like this:

describe(&#39;opening and closing modal&#39;, () =&gt; {
    test(&#39;should open modal when button is clicked&#39;, () =&gt; {
       // better to select on what the user is looking for
       const btn = screen.getByText(&#39;Open modal&#39;);
       // don&#39;t need to check if it is in the document, bc fireEvent will error if it is not
       fireEvent.click(btn);
       expect(screen.getByTestId(&#39;my-modal&#39;)).toBeVisible();
    });
    test(&#39;should close modal when background clicked&#39;, () =&gt; {
       const btn = screen.getByText(&#39;Open modal&#39;);
       fireEvent.click(btn);

       fireEvent.click(screen);
       expect(screen.getByTestId(&#39;my-modal&#39;)).not.toBeVisible();
    });
});

HTH

huangapple
  • 本文由 发表于 2023年7月18日 04:55:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76708009.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定