无法构建测试以使用 OnClickOutside 自定义挂钩
can't build test to useOnClickOutside custom hook
我构建了一个自定义挂钩,我想从中构建测试,但我不知道从哪里开始我希望你能帮我解释一些事情:
1.how 我在测试中捕获了 mousedown
2. 我如何使用 useRef 并将其分配给当前值
如果你能帮助我并向我展示代码,那将非常有帮助,因为我有时会坐在上面
下面是自定义挂钩和我实现自定义挂钩的代码
提前致谢
import { useEffect } from 'react';
function useOnClickOutside(ref, callback) {
useEffect(
() => {
const listener = (event) => {
// Do nothing if clicking ref's element or descendent elements
if (!ref.current || ref.current.contains(event.target)) {
return;
}
callback(event);
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
},
[ref, callback],
);
}
export default useOnClickOutside;
这是使用它的组件:
import React, { useRef, useEffect } from 'react';
import ReactDOM from 'react-dom';
import styles from './OverlayDialog.module.css';
import useOnClickOutside from '../../CustomeHooks/useOnClickOutside/useOnClickOutside';
const OverlayDialog = (props) => {
const wrapperRef = useRef(null);
useEffect(() => {
window.addEventListener("mousedown", handleClickOutside);
return () => {
window.removeEventListener("mousedown", handleClickOutside);
};
});
const handleClickOutside = event => {
const { current: wrap } = wrapperRef;
if (wrap && !wrap.contains(event.target)) {
props.onClose(false);
}
};
useOnClickOutside( wrapperRef,()=>props.onClose(false))
return ReactDOM.createPortal(
<div className={styles.Dialog}>
<div className={styles.InnerDialog} tabIndex={1}>
<div className={styles.DialogCard} tabIndex={-1}>
<div className={props.className ? props.className : styles.DialogContent} ref={wrapperRef}>
{props.children}
</div>
</div>
</div>
</div>,
document.getElementById('OverlayDialog')
)
}
export default OverlayDialog;
我找到了适合您的案例的好博客 post。有关如何测试 onClickOutside https://webman.pro/blog/how-to-detect-and-test-click-outside-in-react/ 的信息
我查看了您的组件,很好奇它的实际工作原理)因此,如果您添加代码的实时示例,我可以为您提供更多帮助)
更新
我为您的组件中的内容添加了测试 ID)
组件:
import React, { useRef } from "react";
import ReactDOM from "react-dom";
import styles from "./OverlayDialog.module.css";
import useOnClickOutside from "./useOnClickOutside";
const OverlayDialog = (props) => {
const wrapperRef = useRef(null);
useOnClickOutside(wrapperRef, () => props.onClose());
return ReactDOM.createPortal(
<div className={styles.Dialog}>
<div className={styles.InnerDialog} tabIndex={1}>
<div className={styles.DialogCard} tabIndex={-1}>
<div
className={props.className ? props.className : styles.DialogContent}
ref={wrapperRef}
data-testid="content"
>
{props.children}
</div>
</div>
</div>
</div>,
document.getElementById("OverlayDialog")
);
};
export default OverlayDialog;
测试:
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import OverlayDialog from "./OverlayDialog";
test('renders learn react link', () => {
const onClose = jest.fn();
const modalRoot = document.createElement('div');
modalRoot.setAttribute('id', 'OverlayDialog');
const body = document.querySelector('body');
body.appendChild(modalRoot);
render(
<OverlayDialog onClose={onClose}>
content
</OverlayDialog>
);
/*checking that if we click on content nothing happens*/
expect(screen.queryByTestId('content')).toBeInTheDocument();
fireEvent(screen.queryByTestId('content'), new MouseEvent('mousedown', {
bubbles: true,
cancelable: true,
}));
expect(onClose).not.toBeCalled();
/*checking that if we click outside we'll fire onClose*/
fireEvent(body, new MouseEvent('mousedown', {
bubbles: true,
cancelable: true,
}));
expect(onClose).toBeCalled();
});
隔离测试 useOnClickOutside 的示例
import { createRef } from 'react';
import { renderHook } from '@testing-library/react-hooks';
import { fireEvent, render, screen } from '@testing-library/react';
import useOnClickOutside from './useOnClickOutside';
describe('useOnClickOutside', () => {
it('calls handler when click is outside element', () => {
// Arrange
const handler = jest.fn();
const ref = createRef<HTMLDivElement>();
render(<div ref={ref}></div>);
// Act
renderHook(() => useOnClickOutside(ref, handler));
fireEvent.click(document);
// Assert
expect(handler).toBeCalledTimes(1);
});
it(`doesn't calls handler when click is within element`, () => {
// Arrange
const handler = jest.fn();
const ref = createRef<HTMLDivElement>();
render(<div ref={ref} data-testid="element-testid"></div>);
// Act
renderHook(() => useOnClickOutside(ref, handler));
fireEvent.click(screen.getByTestId('element-testid'));
// Assert
expect(handler).not.toBeCalled();
});
});
我构建了一个自定义挂钩,我想从中构建测试,但我不知道从哪里开始我希望你能帮我解释一些事情:
1.how 我在测试中捕获了 mousedown 2. 我如何使用 useRef 并将其分配给当前值 如果你能帮助我并向我展示代码,那将非常有帮助,因为我有时会坐在上面
下面是自定义挂钩和我实现自定义挂钩的代码 提前致谢
import { useEffect } from 'react';
function useOnClickOutside(ref, callback) {
useEffect(
() => {
const listener = (event) => {
// Do nothing if clicking ref's element or descendent elements
if (!ref.current || ref.current.contains(event.target)) {
return;
}
callback(event);
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
},
[ref, callback],
);
}
export default useOnClickOutside;
这是使用它的组件:
import React, { useRef, useEffect } from 'react';
import ReactDOM from 'react-dom';
import styles from './OverlayDialog.module.css';
import useOnClickOutside from '../../CustomeHooks/useOnClickOutside/useOnClickOutside';
const OverlayDialog = (props) => {
const wrapperRef = useRef(null);
useEffect(() => {
window.addEventListener("mousedown", handleClickOutside);
return () => {
window.removeEventListener("mousedown", handleClickOutside);
};
});
const handleClickOutside = event => {
const { current: wrap } = wrapperRef;
if (wrap && !wrap.contains(event.target)) {
props.onClose(false);
}
};
useOnClickOutside( wrapperRef,()=>props.onClose(false))
return ReactDOM.createPortal(
<div className={styles.Dialog}>
<div className={styles.InnerDialog} tabIndex={1}>
<div className={styles.DialogCard} tabIndex={-1}>
<div className={props.className ? props.className : styles.DialogContent} ref={wrapperRef}>
{props.children}
</div>
</div>
</div>
</div>,
document.getElementById('OverlayDialog')
)
}
export default OverlayDialog;
我找到了适合您的案例的好博客 post。有关如何测试 onClickOutside https://webman.pro/blog/how-to-detect-and-test-click-outside-in-react/ 的信息 我查看了您的组件,很好奇它的实际工作原理)因此,如果您添加代码的实时示例,我可以为您提供更多帮助)
更新 我为您的组件中的内容添加了测试 ID) 组件:
import React, { useRef } from "react";
import ReactDOM from "react-dom";
import styles from "./OverlayDialog.module.css";
import useOnClickOutside from "./useOnClickOutside";
const OverlayDialog = (props) => {
const wrapperRef = useRef(null);
useOnClickOutside(wrapperRef, () => props.onClose());
return ReactDOM.createPortal(
<div className={styles.Dialog}>
<div className={styles.InnerDialog} tabIndex={1}>
<div className={styles.DialogCard} tabIndex={-1}>
<div
className={props.className ? props.className : styles.DialogContent}
ref={wrapperRef}
data-testid="content"
>
{props.children}
</div>
</div>
</div>
</div>,
document.getElementById("OverlayDialog")
);
};
export default OverlayDialog;
测试:
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import OverlayDialog from "./OverlayDialog";
test('renders learn react link', () => {
const onClose = jest.fn();
const modalRoot = document.createElement('div');
modalRoot.setAttribute('id', 'OverlayDialog');
const body = document.querySelector('body');
body.appendChild(modalRoot);
render(
<OverlayDialog onClose={onClose}>
content
</OverlayDialog>
);
/*checking that if we click on content nothing happens*/
expect(screen.queryByTestId('content')).toBeInTheDocument();
fireEvent(screen.queryByTestId('content'), new MouseEvent('mousedown', {
bubbles: true,
cancelable: true,
}));
expect(onClose).not.toBeCalled();
/*checking that if we click outside we'll fire onClose*/
fireEvent(body, new MouseEvent('mousedown', {
bubbles: true,
cancelable: true,
}));
expect(onClose).toBeCalled();
});
隔离测试 useOnClickOutside 的示例
import { createRef } from 'react';
import { renderHook } from '@testing-library/react-hooks';
import { fireEvent, render, screen } from '@testing-library/react';
import useOnClickOutside from './useOnClickOutside';
describe('useOnClickOutside', () => {
it('calls handler when click is outside element', () => {
// Arrange
const handler = jest.fn();
const ref = createRef<HTMLDivElement>();
render(<div ref={ref}></div>);
// Act
renderHook(() => useOnClickOutside(ref, handler));
fireEvent.click(document);
// Assert
expect(handler).toBeCalledTimes(1);
});
it(`doesn't calls handler when click is within element`, () => {
// Arrange
const handler = jest.fn();
const ref = createRef<HTMLDivElement>();
render(<div ref={ref} data-testid="element-testid"></div>);
// Act
renderHook(() => useOnClickOutside(ref, handler));
fireEvent.click(screen.getByTestId('element-testid'));
// Assert
expect(handler).not.toBeCalled();
});
});