英文:
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("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);
});
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('opening and closing modal', () => {
test('should open modal when button is clicked', () => {
// better to select on what the user is looking for
const btn = screen.getByText('Open modal');
// don't need to check if it is in the document, bc fireEvent will error if it is not
fireEvent.click(btn);
expect(screen.getByTestId('my-modal')).toBeVisible();
});
test('should close modal when background clicked', () => {
const btn = screen.getByText('Open modal');
fireEvent.click(btn);
fireEvent.click(screen);
expect(screen.getByTestId('my-modal')).not.toBeVisible();
});
});
HTH
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论