From 48b1058e1d86e387cb440cc39082d38eb1a9cad4 Mon Sep 17 00:00:00 2001 From: MadCcc <1075746765@qq.com> Date: Thu, 20 Apr 2023 11:50:32 +0800 Subject: [PATCH 1/3] chore: migrate father --- .fatherrc.js | 9 ------ .fatherrc.ts | 5 ++++ package.json | 3 +- src/Dropdown.tsx | 77 +++++++++++++++++++++++++++++------------------- tsconfig.json | 2 +- 5 files changed, 54 insertions(+), 42 deletions(-) delete mode 100644 .fatherrc.js create mode 100644 .fatherrc.ts diff --git a/.fatherrc.js b/.fatherrc.js deleted file mode 100644 index 912aa0a..0000000 --- a/.fatherrc.js +++ /dev/null @@ -1,9 +0,0 @@ -export default { - cjs: 'babel', - esm: { type: 'babel', importLibToEs: true }, - preCommit: { - eslint: true, - prettier: true, - }, - runtimeHelpers: true, -}; diff --git a/.fatherrc.ts b/.fatherrc.ts new file mode 100644 index 0000000..a5e7c0d --- /dev/null +++ b/.fatherrc.ts @@ -0,0 +1,5 @@ +import { defineConfig } from "father"; + +export default defineConfig({ + plugins: ["@rc-component/father-plugin"], +}); diff --git a/package.json b/package.json index 679c931..1203ed0 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "rc-util": "^5.17.0" }, "devDependencies": { + "@rc-component/father-plugin": "^1.0.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", "@types/classnames": "^2.2.6", @@ -59,7 +60,7 @@ "@types/warning": "^3.0.0", "cross-env": "^7.0.0", "dumi": "^1.1.38", - "father": "^2.13.2", + "father": "^4.0.0", "husky": "^8.0.3", "jest-environment-jsdom": "^29.5.0", "jquery": "^3.3.1", diff --git a/src/Dropdown.tsx b/src/Dropdown.tsx index 1dc64fc..1e37d35 100644 --- a/src/Dropdown.tsx +++ b/src/Dropdown.tsx @@ -1,28 +1,28 @@ -import * as React from 'react'; -import Trigger from '@rc-component/trigger'; -import type { TriggerProps } from '@rc-component/trigger'; -import classNames from 'classnames'; +import type { TriggerProps } from "@rc-component/trigger"; +import Trigger from "@rc-component/trigger"; import type { - AnimationType, + ActionType, AlignType, + AnimationType, BuildInPlacements, - ActionType, -} from '@rc-component/trigger/lib/interface'; -import Placements from './placements'; -import useAccessibility from './hooks/useAccessibility'; -import Overlay from './Overlay'; -import { composeRef, supportRef } from 'rc-util/lib/ref'; -import { ReactElement } from 'react'; +} from "@rc-component/trigger/lib/interface"; +import classNames from "classnames"; +import { composeRef, supportRef } from "rc-util/lib/ref"; +import type { ReactElement } from "react"; +import React from "react"; +import useAccessibility from "./hooks/useAccessibility"; +import Overlay from "./Overlay"; +import Placements from "./placements"; export interface DropdownProps extends Pick< TriggerProps, - | 'getPopupContainer' - | 'children' - | 'mouseEnterDelay' - | 'mouseLeaveDelay' - | 'onPopupAlign' - | 'builtinPlacements' + | "getPopupContainer" + | "children" + | "mouseEnterDelay" + | "mouseLeaveDelay" + | "onPopupAlign" + | "builtinPlacements" > { minOverlayWidthMatchTrigger?: boolean; arrow?: boolean; @@ -49,11 +49,11 @@ export interface DropdownProps function Dropdown(props: DropdownProps, ref) { const { arrow = false, - prefixCls = 'rc-dropdown', + prefixCls = "rc-dropdown", transitionName, animation, align, - placement = 'bottomLeft', + placement = "bottomLeft", placements = Placements, getPopupContainer, showAction, @@ -61,7 +61,7 @@ function Dropdown(props: DropdownProps, ref) { overlayClassName, overlayStyle, visible, - trigger = ['hover'], + trigger = ["hover"], autoFocus, overlay, children, @@ -70,7 +70,7 @@ function Dropdown(props: DropdownProps, ref) { } = props; const [triggerVisible, setTriggerVisible] = React.useState(); - const mergedVisible = 'visible' in props ? visible : triggerVisible; + const mergedVisible = "visible" in props ? visible : triggerVisible; const triggerRef = React.useRef(null); const overlayRef = React.useRef(null); @@ -99,10 +99,17 @@ function Dropdown(props: DropdownProps, ref) { } }; - const getMenuElement = () => + const getMenuElement = () => ( + + ); const getMenuElementOrLambda = () => { - if (typeof overlay === 'function') { + if (typeof overlay === "function") { return getMenuElement; } return getMenuElement(); @@ -110,7 +117,7 @@ function Dropdown(props: DropdownProps, ref) { const getMinOverlayWidthMatchTrigger = () => { const { minOverlayWidthMatchTrigger, alignPoint } = props; - if ('minOverlayWidthMatchTrigger' in props) { + if ("minOverlayWidthMatchTrigger" in props) { return minOverlayWidthMatchTrigger; } @@ -126,13 +133,21 @@ function Dropdown(props: DropdownProps, ref) { }; const childrenNode = React.cloneElement(children, { - className: classNames(children.props?.className, mergedVisible && getOpenClassName()), - ref: supportRef(children) ? composeRef(childRef, (children as ReactElement & {ref: React.Ref}).ref) : undefined, - }) + className: classNames( + children.props?.className, + mergedVisible && getOpenClassName() + ), + ref: supportRef(children) + ? composeRef( + childRef, + (children as ReactElement & { ref: React.Ref }).ref + ) + : undefined, + }); let triggerHideAction = hideAction; - if (!triggerHideAction && trigger.indexOf('contextMenu') !== -1) { - triggerHideAction = ['click']; + if (!triggerHideAction && trigger.indexOf("contextMenu") !== -1) { + triggerHideAction = ["click"]; } return ( @@ -153,7 +168,7 @@ function Dropdown(props: DropdownProps, ref) { popupTransitionName={transitionName} popupAnimation={animation} popupVisible={mergedVisible} - stretch={getMinOverlayWidthMatchTrigger() ? 'minWidth' : ''} + stretch={getMinOverlayWidthMatchTrigger() ? "minWidth" : ""} popup={getMenuElementOrLambda()} onPopupVisibleChange={handleVisibleChange} onPopupClick={onClick} diff --git a/tsconfig.json b/tsconfig.json index c6bd6b6..6b571e9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ "module": "esnext", "target": "esnext", "moduleResolution": "node", - "jsx": "react-jsx", + "jsx": "react", "skipLibCheck": true }, "include": ["./src", "./tests", "./typings/"], From cdf1bc129117580ceb62d71718b29564f43f14f3 Mon Sep 17 00:00:00 2001 From: MadCcc <1075746765@qq.com> Date: Thu, 20 Apr 2023 11:52:50 +0800 Subject: [PATCH 2/3] chore: add .prettierrc --- .prettierrc | 8 +++++++ src/Dropdown.tsx | 54 ++++++++++++++++++++++++------------------------ 2 files changed, 35 insertions(+), 27 deletions(-) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..77778f6 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "endOfLine": "lf", + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "all", + "proseWrap": "never" +} diff --git a/src/Dropdown.tsx b/src/Dropdown.tsx index 1e37d35..fec2121 100644 --- a/src/Dropdown.tsx +++ b/src/Dropdown.tsx @@ -1,28 +1,28 @@ -import type { TriggerProps } from "@rc-component/trigger"; -import Trigger from "@rc-component/trigger"; +import type { TriggerProps } from '@rc-component/trigger'; +import Trigger from '@rc-component/trigger'; import type { ActionType, AlignType, AnimationType, BuildInPlacements, -} from "@rc-component/trigger/lib/interface"; -import classNames from "classnames"; -import { composeRef, supportRef } from "rc-util/lib/ref"; -import type { ReactElement } from "react"; -import React from "react"; -import useAccessibility from "./hooks/useAccessibility"; -import Overlay from "./Overlay"; -import Placements from "./placements"; +} from '@rc-component/trigger/lib/interface'; +import classNames from 'classnames'; +import { composeRef, supportRef } from 'rc-util/lib/ref'; +import type { ReactElement } from 'react'; +import React from 'react'; +import useAccessibility from './hooks/useAccessibility'; +import Overlay from './Overlay'; +import Placements from './placements'; export interface DropdownProps extends Pick< TriggerProps, - | "getPopupContainer" - | "children" - | "mouseEnterDelay" - | "mouseLeaveDelay" - | "onPopupAlign" - | "builtinPlacements" + | 'getPopupContainer' + | 'children' + | 'mouseEnterDelay' + | 'mouseLeaveDelay' + | 'onPopupAlign' + | 'builtinPlacements' > { minOverlayWidthMatchTrigger?: boolean; arrow?: boolean; @@ -49,11 +49,11 @@ export interface DropdownProps function Dropdown(props: DropdownProps, ref) { const { arrow = false, - prefixCls = "rc-dropdown", + prefixCls = 'rc-dropdown', transitionName, animation, align, - placement = "bottomLeft", + placement = 'bottomLeft', placements = Placements, getPopupContainer, showAction, @@ -61,7 +61,7 @@ function Dropdown(props: DropdownProps, ref) { overlayClassName, overlayStyle, visible, - trigger = ["hover"], + trigger = ['hover'], autoFocus, overlay, children, @@ -70,7 +70,7 @@ function Dropdown(props: DropdownProps, ref) { } = props; const [triggerVisible, setTriggerVisible] = React.useState(); - const mergedVisible = "visible" in props ? visible : triggerVisible; + const mergedVisible = 'visible' in props ? visible : triggerVisible; const triggerRef = React.useRef(null); const overlayRef = React.useRef(null); @@ -109,7 +109,7 @@ function Dropdown(props: DropdownProps, ref) { ); const getMenuElementOrLambda = () => { - if (typeof overlay === "function") { + if (typeof overlay === 'function') { return getMenuElement; } return getMenuElement(); @@ -117,7 +117,7 @@ function Dropdown(props: DropdownProps, ref) { const getMinOverlayWidthMatchTrigger = () => { const { minOverlayWidthMatchTrigger, alignPoint } = props; - if ("minOverlayWidthMatchTrigger" in props) { + if ('minOverlayWidthMatchTrigger' in props) { return minOverlayWidthMatchTrigger; } @@ -135,19 +135,19 @@ function Dropdown(props: DropdownProps, ref) { const childrenNode = React.cloneElement(children, { className: classNames( children.props?.className, - mergedVisible && getOpenClassName() + mergedVisible && getOpenClassName(), ), ref: supportRef(children) ? composeRef( childRef, - (children as ReactElement & { ref: React.Ref }).ref + (children as ReactElement & { ref: React.Ref }).ref, ) : undefined, }); let triggerHideAction = hideAction; - if (!triggerHideAction && trigger.indexOf("contextMenu") !== -1) { - triggerHideAction = ["click"]; + if (!triggerHideAction && trigger.indexOf('contextMenu') !== -1) { + triggerHideAction = ['click']; } return ( @@ -168,7 +168,7 @@ function Dropdown(props: DropdownProps, ref) { popupTransitionName={transitionName} popupAnimation={animation} popupVisible={mergedVisible} - stretch={getMinOverlayWidthMatchTrigger() ? "minWidth" : ""} + stretch={getMinOverlayWidthMatchTrigger() ? 'minWidth' : ''} popup={getMenuElementOrLambda()} onPopupVisibleChange={handleVisibleChange} onPopupClick={onClick} From 7eae76cbe58bcc9372e07af83e624ba41d8fd984 Mon Sep 17 00:00:00 2001 From: MadCcc <1075746765@qq.com> Date: Thu, 20 Apr 2023 16:37:37 +0800 Subject: [PATCH 3/3] chore: test case --- tests/basic.test.tsx | 297 +++++++++++++++++++++++-------------------- 1 file changed, 156 insertions(+), 141 deletions(-) diff --git a/tests/basic.test.tsx b/tests/basic.test.tsx index e4d8c36..2949961 100644 --- a/tests/basic.test.tsx +++ b/tests/basic.test.tsx @@ -1,17 +1,14 @@ /* eslint-disable react/button-has-type,react/no-find-dom-node,react/no-render-return-value,object-shorthand,func-names,max-len */ -import { act, fireEvent } from "@testing-library/react"; -import Menu, { Divider, Item as MenuItem, MenuRef } from "rc-menu"; -import { _rs } from "rc-resize-observer"; -import { spyElementPrototypes } from "rc-util/lib/test/domHook"; -import * as React from "react"; -import { - createRef, - forwardRef, - HTMLAttributes, - useImperativeHandle, -} from "react"; -import Dropdown from "../src"; -import { render, sleep } from "./utils"; +import { act, fireEvent } from '@testing-library/react'; +import type { MenuRef } from 'rc-menu'; +import Menu, { Divider, Item as MenuItem } from 'rc-menu'; +import { _rs } from 'rc-resize-observer'; +import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; +import type { HTMLAttributes } from 'react'; +import * as React from 'react'; +import { createRef, forwardRef, useImperativeHandle } from 'react'; +import Dropdown from '../src'; +import { render, sleep } from './utils'; // Fix prettier rm this console.log(!!React); @@ -63,49 +60,49 @@ spyElementPrototypes(HTMLElement, { }), }); -describe("dropdown", () => { +describe('dropdown', () => { beforeEach(() => { jest.clearAllTimers(); }); - it("default visible", () => { + it('default visible', () => { const { container } = render( Test} visible> - + , ); expect(container instanceof HTMLDivElement).toBeTruthy(); expect( container - .querySelector(".my-button") - ?.classList.contains("rc-dropdown-open") + .querySelector('.my-button') + ?.classList.contains('rc-dropdown-open'), ).toBeTruthy(); }); - it("supports controlled visible prop", () => { + it('supports controlled visible prop', () => { const onVisibleChange = jest.fn(); const { container } = render( Test} visible - trigger={["click"]} + trigger={['click']} onVisibleChange={onVisibleChange} > - + , ); expect(container instanceof HTMLDivElement).toBeTruthy(); expect( container - .querySelector(".my-button") - ?.classList.contains("rc-dropdown-open") + .querySelector('.my-button') + ?.classList.contains('rc-dropdown-open'), ).toBeTruthy(); - fireEvent.click(container.querySelector(".my-button")); + fireEvent.click(container.querySelector('.my-button')); expect(onVisibleChange).toHaveBeenCalledWith(false); }); - it("simply works", async () => { + it('simply works', async () => { let clicked; function onClick({ key }) { @@ -125,37 +122,37 @@ describe("dropdown", () => { ); const { container, baseElement } = render( - + , ); - expect(container.querySelector(".my-button")).toBeTruthy(); + expect(container.querySelector('.my-button')).toBeTruthy(); // should not display until be triggered - expect(baseElement.querySelector(".rc-dropdown")).toBeFalsy(); + expect(baseElement.querySelector('.rc-dropdown')).toBeFalsy(); - fireEvent.click(container.querySelector(".my-button")); + fireEvent.click(container.querySelector('.my-button')); expect(clicked).toBeUndefined(); expect( baseElement - .querySelector(".rc-dropdown") - .classList.contains("rc-dropdown-hidden") + .querySelector('.rc-dropdown') + .classList.contains('rc-dropdown-hidden'), ).toBeFalsy(); expect(container).toMatchSnapshot(); - fireEvent.click(baseElement.querySelector(".my-menuitem")); - expect(clicked).toBe("1"); + fireEvent.click(baseElement.querySelector('.my-menuitem')); + expect(clicked).toBe('1'); expect(onOverlayClick).toHaveBeenCalled(); expect( baseElement - .querySelector(".rc-dropdown") - .classList.contains("rc-dropdown-hidden") + .querySelector('.rc-dropdown') + .classList.contains('rc-dropdown-hidden'), ).toBeTruthy(); }); - it("re-align works", async () => { + it('re-align works', async () => { jest.useFakeTimers(); const onPopupAlign = jest.fn(); @@ -168,7 +165,7 @@ describe("dropdown", () => { ); const { container } = render( { - + , ); expect(onPopupAlign).not.toHaveBeenCalled(); - fireEvent.click(container.querySelector(".my-btn")); + fireEvent.click(container.querySelector('.my-btn')); await waitForTime(); expect(onPopupAlign).toHaveBeenCalled(); @@ -189,30 +186,30 @@ describe("dropdown", () => { jest.useRealTimers(); }); - it("Test default minOverlayWidthMatchTrigger", async () => { + it('Test default minOverlayWidthMatchTrigger', async () => { jest.useFakeTimers(); const overlayWidth = 50; const overlay =
Test
; const { container, baseElement } = render( - + - + , ); - await triggerResize(container.querySelector("button")); + await triggerResize(container.querySelector('button')); - expect(baseElement.querySelector(".rc-dropdown")).toHaveStyle({ - minWidth: "100px", + expect(baseElement.querySelector('.rc-dropdown')).toHaveStyle({ + minWidth: '100px', }); jest.useRealTimers(); }); - it("user pass minOverlayWidthMatchTrigger", async () => { + it('user pass minOverlayWidthMatchTrigger', async () => { jest.useFakeTimers(); const overlayWidth = 50; @@ -220,7 +217,7 @@ describe("dropdown", () => { const { container, baseElement } = render( { - + , ); - await triggerResize(container.querySelector("button")); + await triggerResize(container.querySelector('button')); - expect(baseElement.querySelector(".rc-dropdown")).not.toHaveStyle({ - minWidth: "100px", + expect(baseElement.querySelector('.rc-dropdown')).not.toHaveStyle({ + minWidth: '100px', }); jest.useRealTimers(); }); - it("should support default openClassName", () => { + it('should support default openClassName', () => { const overlay =
Test
; const { container } = render( - + , ); - fireEvent.click(container.querySelector(".my-button")); + fireEvent.click(container.querySelector('.my-button')); expect( container - .querySelector(".my-button") - .classList.contains("rc-dropdown-open") + .querySelector('.my-button') + .classList.contains('rc-dropdown-open'), ).toBeTruthy(); - fireEvent.click(container.querySelector(".my-button")); + fireEvent.click(container.querySelector('.my-button')); expect( container - .querySelector(".my-button") - .classList.contains("rc-dropdown-open") + .querySelector('.my-button') + .classList.contains('rc-dropdown-open'), ).toBeFalsy(); }); - it("should support custom openClassName", async () => { + it('should support custom openClassName', async () => { const overlay =
Test
; const { container } = render( { - + , ); - fireEvent.click(container.querySelector(".my-button")); + fireEvent.click(container.querySelector('.my-button')); expect( - container.querySelector(".my-button").classList.contains("opened") + container.querySelector('.my-button').classList.contains('opened'), ).toBeTruthy(); - fireEvent.click(container.querySelector(".my-button")); + fireEvent.click(container.querySelector('.my-button')); expect( - container.querySelector(".my-button").classList.contains("opened") + container.querySelector('.my-button').classList.contains('opened'), ).toBeFalsy(); }); - it("overlay callback", async () => { + it('overlay callback', async () => { const overlay =
Test
; const { container, baseElement } = render( - overlay}> + overlay}> - + , ); - fireEvent.click(container.querySelector(".my-button")); + fireEvent.click(container.querySelector('.my-button')); expect( baseElement - .querySelector(".rc-dropdown") - .classList.contains("rc-dropdown-hidden") + .querySelector('.rc-dropdown') + .classList.contains('rc-dropdown-hidden'), ).toBeFalsy(); }); - it("should support arrow", async () => { + it('should support arrow', async () => { const overlay =
Test
; const { container, baseElement } = render( - + - + , ); - fireEvent.click(container.querySelector(".my-button")); + fireEvent.click(container.querySelector('.my-button')); await sleep(500); expect( baseElement - .querySelector(".rc-dropdown") - .classList.contains("rc-dropdown-show-arrow") + .querySelector('.rc-dropdown') + .classList.contains('rc-dropdown-show-arrow'), ).toBeTruthy(); expect( baseElement - .querySelector(".rc-dropdown") - .firstElementChild.classList.contains("rc-dropdown-arrow") + .querySelector('.rc-dropdown') + .firstElementChild.classList.contains('rc-dropdown-arrow'), ).toBeTruthy(); }); - it("Keyboard navigation works", async () => { + it('Keyboard navigation works', async () => { jest.useFakeTimers(); const overlay = ( @@ -344,90 +341,90 @@ describe("dropdown", () => { ); const { container, baseElement } = render( - + - + , ); - const trigger = container.querySelector(".my-button"); + const trigger = container.querySelector('.my-button'); // Open menu; fireEvent.click(trigger); await waitForTime(); expect( baseElement - .querySelector(".rc-dropdown") - .classList.contains("rc-dropdown-hidden") + .querySelector('.rc-dropdown') + .classList.contains('rc-dropdown-hidden'), ).toBeFalsy(); // Close menu with Esc - fireEvent.keyDown(window, { key: "Esc", keyCode: 27 }); + fireEvent.keyDown(window, { key: 'Esc', keyCode: 27 }); await waitForTime(); - expect(document.activeElement.className).toContain("my-button"); + expect(document.activeElement.className).toContain('my-button'); // Open menu fireEvent.click(trigger); await waitForTime(); expect( baseElement - .querySelector(".rc-dropdown") - .classList.contains("rc-dropdown-hidden") + .querySelector('.rc-dropdown') + .classList.contains('rc-dropdown-hidden'), ).toBeFalsy(); // Focus menu with Tab - window.dispatchEvent(new KeyboardEvent("keydown", { keyCode: 9 })); // Tab - expect(document.activeElement.className).toContain("menu"); + window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 9 })); // Tab + expect(document.activeElement.className).toContain('menu'); // Close menu with Tab - window.dispatchEvent(new KeyboardEvent("keydown", { keyCode: 9 })); // Tab + window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 9 })); // Tab await waitForTime(); - expect(document.activeElement.className).toContain("my-button"); + expect(document.activeElement.className).toContain('my-button'); jest.useRealTimers(); }); - it("Tab should close menu if overlay cannot be focused", async () => { + it('Tab should close menu if overlay cannot be focused', async () => { jest.useFakeTimers(); const Overlay = () =>
test
; const { container, baseElement } = render( - }> + }> - + , ); - const trigger = container.querySelector(".my-button"); + const trigger = container.querySelector('.my-button'); // Open menu; fireEvent.click(trigger); await waitForTime(); expect( baseElement - .querySelector(".rc-dropdown") - .classList.contains("rc-dropdown-hidden") + .querySelector('.rc-dropdown') + .classList.contains('rc-dropdown-hidden'), ).toBeFalsy(); // Close menu with Esc - fireEvent.keyDown(window, { key: "Esc", keyCode: 27 }); + fireEvent.keyDown(window, { key: 'Esc', keyCode: 27 }); await waitForTime(); - expect(document.activeElement.className).toContain("my-button"); + expect(document.activeElement.className).toContain('my-button'); // Open menu fireEvent.click(trigger); await waitForTime(); expect( baseElement - .querySelector(".rc-dropdown") - .classList.contains("rc-dropdown-hidden") + .querySelector('.rc-dropdown') + .classList.contains('rc-dropdown-hidden'), ).toBeFalsy(); // Close menu with Tab - window.dispatchEvent(new KeyboardEvent("keydown", { keyCode: 9 })); // Tab + window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 9 })); // Tab await waitForTime(); - expect(document.activeElement.className).toContain("my-button"); + expect(document.activeElement.className).toContain('my-button'); jest.useRealTimers(); }); - it("keyboard should work if menu is wrapped", async () => { + it('keyboard should work if menu is wrapped', async () => { const overlay = (
@@ -439,45 +436,45 @@ describe("dropdown", () => {
); const { container, baseElement } = render( - + - + , ); - const trigger = container.querySelector(".my-button"); + const trigger = container.querySelector('.my-button'); // Open menu fireEvent.click(trigger); await sleep(200); expect( baseElement - .querySelector(".rc-dropdown") - .classList.contains("rc-dropdown-hidden") + .querySelector('.rc-dropdown') + .classList.contains('rc-dropdown-hidden'), ).toBeFalsy(); // Close menu with Esc - window.dispatchEvent(new KeyboardEvent("keydown", { keyCode: 27 })); // Esc + window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 27 })); // Esc await sleep(200); - expect(document.activeElement.className).toContain("my-button"); + expect(document.activeElement.className).toContain('my-button'); // Open menu fireEvent.click(trigger); await sleep(200); expect( baseElement - .querySelector(".rc-dropdown") - .classList.contains("rc-dropdown-hidden") + .querySelector('.rc-dropdown') + .classList.contains('rc-dropdown-hidden'), ).toBeFalsy(); // Focus menu with Tab - window.dispatchEvent(new KeyboardEvent("keydown", { keyCode: 9 })); // Tab + window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 9 })); // Tab // Close menu with Tab - window.dispatchEvent(new KeyboardEvent("keydown", { keyCode: 9 })); // Tab + window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 9 })); // Tab await sleep(200); - expect(document.activeElement.className).toContain("my-button"); + expect(document.activeElement.className).toContain('my-button'); }); - it("support Menu expandIcon", async () => { + it('support Menu expandIcon', async () => { const props = { overlay: ( }> @@ -494,13 +491,13 @@ describe("dropdown", () => { const { container } = render( - + , ); await sleep(500); - expect(container.querySelector("#customExpandIcon")).toBeTruthy(); + expect(container.querySelector('#customExpandIcon')).toBeTruthy(); }); - it("should support customized menuRef", async () => { + it('should support customized menuRef', async () => { const menuRef = createRef(); const props = { overlay: ( @@ -514,14 +511,14 @@ describe("dropdown", () => { render( - + , ); await sleep(500); expect(menuRef.current).toBeTruthy(); }); - it("should support trigger which not support focus", async () => { + it('should support trigger which not support focus', async () => { jest.useFakeTimers(); const Button = forwardRef>( (props, ref) => { @@ -537,11 +534,11 @@ describe("dropdown", () => { trigger ); - } + }, ); const { container, baseElement } = render( node} overlay={ @@ -550,16 +547,16 @@ describe("dropdown", () => { } > ); const { container } = render( - + - + , ); - const trigger = container.querySelector(".my-button"); + const trigger = container.querySelector('.my-button'); // Open menu fireEvent.click(trigger); @@ -584,18 +581,36 @@ describe("dropdown", () => { expect( container - .querySelector(".rc-dropdown") - .classList.contains("rc-dropdown-hidden") + .querySelector('.rc-dropdown') + .classList.contains('rc-dropdown-hidden'), ).toBeFalsy(); - expect(document.activeElement.className).toContain("menu"); + expect(document.activeElement.className).toContain('menu'); // Close menu with Tab - window.dispatchEvent(new KeyboardEvent("keydown", { keyCode: 9 })); // Tab + window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 9 })); // Tab await waitForTime(); - expect(document.activeElement.className).toContain("my-button"); + expect(document.activeElement.className).toContain('my-button'); jest.useRealTimers(); }); + + it('children cannot be given ref should not throw', () => { + const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + const Component = () =>
test
; + + render( + test}> + + , + ); + expect(errorSpy).not.toHaveBeenCalledWith( + expect.stringContaining( + 'Warning: Function components cannot be given refs', + ), + expect.anything(), + expect.anything(), + ); + }); });