无法构建测试以使用 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();
  });
});