fix: lazyMotion forwardRef issue (#2622)

* fix(ripple): lazyMotion forwardRef issue in Ripple

* feat(dropdown): add test case for LazyMotion React.forwardRef issue

* refactor(dropdown): revise the test title

* feat(modal): include console error check in modal test

* feat(popover): add "should not throw error when clicking trigger button" test

* feat(accordion): add test for lazy motion issue

* feat(navbar): add test for lazy motion issue

* feat(tabs): add test for lazy motion issue

* feat(tooltip): add test for lazy motion issue

* refactor(dropdown): remove unnecessary async

* refactor(test): move spy outside and trigger clearAllMocks after each test
This commit is contained in:
աӄա 2024-04-02 22:01:17 +08:00 committed by GitHub
parent a60c2d7b22
commit 2e49e08315
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 177 additions and 26 deletions

View File

@ -0,0 +1,5 @@
---
"@nextui-org/ripple": patch
---
Fixed LazyMotion forwardRef issue

View File

@ -5,7 +5,15 @@ import userEvent from "@testing-library/user-event";
import {Accordion, AccordionItem} from "../src";
// e.g. console.error Warning: Function components cannot be given refs.
// Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
const spy = jest.spyOn(console, "error").mockImplementation(() => {});
describe("Accordion", () => {
afterEach(() => {
jest.clearAllMocks();
});
it("should render correctly", () => {
const wrapper = render(
<Accordion>
@ -14,6 +22,8 @@ describe("Accordion", () => {
);
expect(() => wrapper.unmount()).not.toThrow();
expect(spy).toBeCalledTimes(0);
});
it("ref should be forwarded", () => {

View File

@ -6,7 +6,15 @@ import {User} from "@nextui-org/user";
import {Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, DropdownSection} from "../src";
// e.g. console.error Warning: Function components cannot be given refs.
// Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
const spy = jest.spyOn(console, "error").mockImplementation(() => {});
describe("Dropdown", () => {
afterEach(() => {
jest.clearAllMocks();
});
it("should render correctly (static)", () => {
const wrapper = render(
<Dropdown>
@ -111,6 +119,34 @@ describe("Dropdown", () => {
expect(() => wrapper.unmount()).not.toThrow();
});
it("should not throw any error when clicking button", async () => {
const wrapper = render(
<Dropdown>
<DropdownTrigger>
<Button data-testid="trigger-test">Trigger</Button>
</DropdownTrigger>
<DropdownMenu aria-label="Actions" onAction={alert}>
<DropdownItem key="new">New file</DropdownItem>
<DropdownItem key="copy">Copy link</DropdownItem>
<DropdownItem key="edit">Edit file</DropdownItem>
<DropdownItem key="delete" color="danger">
Delete file
</DropdownItem>
</DropdownMenu>
</Dropdown>,
);
let triggerButton = wrapper.getByTestId("trigger-test");
expect(triggerButton).toBeTruthy();
await act(async () => {
await userEvent.click(triggerButton);
});
expect(spy).toBeCalledTimes(0);
});
it("should work with single selection (controlled)", async () => {
let onOpenChange = jest.fn();
let onSelectionChange = jest.fn();

View File

@ -3,7 +3,15 @@ import {act, render, fireEvent} from "@testing-library/react";
import {Modal, ModalContent, ModalBody, ModalHeader, ModalFooter} from "../src";
// e.g. console.error Warning: Function components cannot be given refs.
// Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
const spy = jest.spyOn(console, "error").mockImplementation(() => {});
describe("Modal", () => {
afterEach(() => {
jest.clearAllMocks();
});
it("should render correctly", () => {
const wrapper = render(
<Modal isOpen>
@ -16,6 +24,8 @@ describe("Modal", () => {
);
expect(() => wrapper.unmount()).not.toThrow();
expect(spy).toBeCalledTimes(0);
});
it("ref should be forwarded", () => {

View File

@ -11,7 +11,16 @@ import {
NavbarMenuItem,
} from "../src";
window.scrollTo = jest.fn();
// e.g. console.error Warning: Function components cannot be given refs.
// Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
const spy = jest.spyOn(console, "error").mockImplementation(() => {});
describe("Navbar", () => {
afterEach(() => {
jest.clearAllMocks();
});
it("should render correctly", () => {
const wrapper = render(<Navbar />);
@ -53,6 +62,36 @@ describe("Navbar", () => {
expect(navbarContent.children.length).toBe(5);
});
it("should not throw error after toggle click", () => {
const items = ["item1", "item2", "item3", "item4", "item5"];
const wrapper = render(
<Navbar data-testid="navbar-test">
<NavbarMenuToggle data-testid="navbar-toggle-test" />
<NavbarContent data-testid="navbar-content-test">
<NavbarItem>Dashboard</NavbarItem>
<NavbarItem>Team</NavbarItem>
<NavbarItem>Deployments</NavbarItem>
<NavbarItem>Activity</NavbarItem>
<NavbarItem>Settings</NavbarItem>
</NavbarContent>
<NavbarMenu data-testid="navbar-menu-test">
{items.map((item, index) => (
<NavbarMenuItem key={`${item}-${index}`}>{item}</NavbarMenuItem>
))}
</NavbarMenu>
</Navbar>,
);
const toggle = wrapper.getByTestId("navbar-toggle-test");
act(() => {
toggle.click();
});
expect(spy).toBeCalledTimes(0);
});
it("should render correctly with menu", () => {
const items = ["item1", "item2", "item3", "item4", "item5"];

View File

@ -4,7 +4,15 @@ import {Button} from "@nextui-org/button";
import {Popover, PopoverContent, PopoverTrigger} from "../src";
// e.g. console.error Warning: Function components cannot be given refs.
// Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
const spy = jest.spyOn(console, "error").mockImplementation(() => {});
describe("Popover", () => {
afterEach(() => {
jest.clearAllMocks();
});
it("should render correctly", () => {
const wrapper = render(
<Popover>
@ -20,6 +28,27 @@ describe("Popover", () => {
expect(() => wrapper.unmount()).not.toThrow();
});
it("should not throw error when clicking trigger button", () => {
const wrapper = render(
<Popover>
<PopoverTrigger>
<button data-testid="trigger-test">Open popover</button>
</PopoverTrigger>
<PopoverContent>
<p>This is the content of the popover.</p>
</PopoverContent>
</Popover>,
);
const trigger = wrapper.getByTestId("trigger-test");
// open popover
act(() => {
trigger.click();
});
expect(spy).toBeCalledTimes(0);
});
it("ref should be forwarded", () => {
const ref = React.createRef<HTMLDivElement>();

View File

@ -26,32 +26,34 @@ const Ripple: FC<RippleProps> = (props) => {
return (
<AnimatePresence key={ripple.key} mode="popLayout">
<LazyMotion features={domAnimation}>
<m.span
animate={{transform: "scale(2)", opacity: 0}}
className="nextui-ripple"
exit={{opacity: 0}}
initial={{transform: "scale(0)", opacity: 0.35}}
style={{
position: "absolute",
backgroundColor: color,
borderRadius: "100%",
transformOrigin: "center",
pointerEvents: "none",
zIndex: 10,
top: ripple.y,
left: ripple.x,
width: `${ripple.size}px`,
height: `${ripple.size}px`,
...style,
}}
transition={{duration}}
onAnimationComplete={() => {
onClear(ripple.key);
}}
{...motionProps}
/>
</LazyMotion>
<>
<LazyMotion features={domAnimation}>
<m.span
animate={{transform: "scale(2)", opacity: 0}}
className="nextui-ripple"
exit={{opacity: 0}}
initial={{transform: "scale(0)", opacity: 0.35}}
style={{
position: "absolute",
backgroundColor: color,
borderRadius: "100%",
transformOrigin: "center",
pointerEvents: "none",
zIndex: 10,
top: ripple.y,
left: ripple.x,
width: `${ripple.size}px`,
height: `${ripple.size}px`,
...style,
}}
transition={{duration}}
onAnimationComplete={() => {
onClear(ripple.key);
}}
{...motionProps}
/>
</LazyMotion>
</>
</AnimatePresence>
);
})}

View File

@ -29,7 +29,15 @@ let tabs: Item[] = [
},
];
// e.g. console.error Warning: Function components cannot be given refs.
// Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
const spy = jest.spyOn(console, "error").mockImplementation(() => {});
describe("Tabs", () => {
afterEach(() => {
jest.clearAllMocks();
});
it("should render correctly (static)", () => {
const wrapper = render(
<Tabs aria-label="Tabs static test">
@ -46,6 +54,8 @@ describe("Tabs", () => {
);
expect(() => wrapper.unmount()).not.toThrow();
expect(spy).toBeCalledTimes(0);
});
it("should render correctly (dynamic)", () => {

View File

@ -4,7 +4,15 @@ import {Button} from "@nextui-org/button";
import {Tooltip} from "../src";
// e.g. console.error Warning: Function components cannot be given refs.
// Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
const spy = jest.spyOn(console, "error").mockImplementation(() => {});
describe("Tooltip", () => {
afterEach(() => {
jest.clearAllMocks();
});
it("should throw error if no children is passed", () => {
const spy = jest.spyOn(console, "warn").mockImplementation(() => {});
@ -21,6 +29,8 @@ describe("Tooltip", () => {
);
expect(() => wrapper.unmount()).not.toThrow();
expect(spy).toBeCalledTimes(0);
});
it("ref should be forwarded", () => {