mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
* fix(autocomplete): autocomplete focus behaviour * feat(autocomplete): add test case for catching blur cases * refactor(autocomplete): use isOpen instead * feat(autocomplete): add "should focus when clicking autocomplete" test case * feat(autocomplete): add should set the input after selection * fix(autocomplete): remove shouldUseVirtualFocus * fix(autocomplete): uncomment blur logic * refactor(autocomplete): remove state as it is in getPopoverProps * refactor(autocomplete): remove unnecessary blur * refactor(select): remove unncessary props * fix(popover): use domRef instead * fix(popover): revise isNonModal and isDismissable * fix(popover): use dialogRef back * fix(popover): rollback * fix(autocomplete): onFocus logic * feat(popover): set disableFocusManagement to overlay * feat(modal): set disableFocusManagement to overlay * fix(autocomplete): set disableFocusManagement for autocomplete * feat(popover): include disableFocusManagement prop * refactor(autocomplete): revise type in selectorButton * fix(autocomplete): revise focus logic * feat(autocomplete): add internal focus state and add shouldCloseOnInteractOutside * feat(autocomplete): handle selectedItem change * feat(autocomplete): add clear button test * feat(changeset): add changeset * refactor(components): use the original order * refactor(autocomplete): add more comments * fix(autocomplete): revise focus behaviours * refactor(autocomplete): rename to listbox * chore(popover): remove disableFocusManagement from popover * chore(autocomplete): remove disableFocusManagement from autocomplete * chore(changeset): add issue number * fix(popover): don't set default value to transformOrigin * fix(autocomplete): revise shouldCloseOnInteractOutside logic * feat(autocomplete): should close listbox by clicking another autocomplete * fix(popover): add disableFocusManagement to overlay * refactor(autocomplete): revise comments and refactor shouldCloseOnInteractOutside * feat(changeset): add issue number * fix(autocomplete): merge with selectorButtonProps.onClick * refactor(autocomplete): remove extra line * refactor(autocomplete): revise comment * feat(select): add shouldCloseOnInteractOutside * feat(dropdown): add shouldCloseOnInteractOutside * feat(date-picker): add shouldCloseOnInteractOutside * feat(changeset): add dropdown and date-picker * fix(popover): revise shouldCloseOnInteractOutside * feat(date-picker): integrate with ariaShouldCloseOnInteractOutside * feat(select): integrate with ariaShouldCloseOnInteractOutside * feat(dropdown): integrate with ariaShouldCloseOnInteractOutside * feat(popover): integrate with ariaShouldCloseOnInteractOutside * feat(aria-utils): ariaShouldCloseOnInteractOutside * chore(deps): update pnpm-lock.yaml * feat(autocomplete): integrate with ariaShouldCloseOnInteractOutside * feat(aria-utils): handle setShouldFocus logic * feat(changeset): add @nextui-org/aria-utils * chore(autocomplete): put the test into correct group * feat(select): should close listbox by clicking another select * feat(dropdown): should close listbox by clicking another dropdown * feat(popover): should close listbox by clicking another popover * feat(date-picker): should close listbox by clicking another datepicker * chore(changeset): add issue numbers and revise changeset message * refactor(autocomplete): change to useRef instead * refactor(autocomplete): change to useRef instead * refactor(aria-utils): revise comments and format code * chore(changeset): add issue number * chore: take popoverProps.shouldCloseOnInteractOutside first * refactor(autocomplete): remove unnecessary logic * refactor(autocomplete): focus management logic
217 lines
5.8 KiB
TypeScript
217 lines
5.8 KiB
TypeScript
import * as React from "react";
|
|
import {render, fireEvent, act} from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
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>
|
|
<PopoverTrigger>
|
|
<button>Open popover</button>
|
|
</PopoverTrigger>
|
|
<PopoverContent>
|
|
<p>This is the content of the popover.</p>
|
|
</PopoverContent>
|
|
</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>();
|
|
|
|
render(
|
|
<Popover ref={ref} defaultOpen>
|
|
<PopoverTrigger>
|
|
<button>Open popover</button>
|
|
</PopoverTrigger>
|
|
<PopoverContent>
|
|
<p>This is the content of the popover.</p>
|
|
</PopoverContent>
|
|
</Popover>,
|
|
);
|
|
expect(ref.current).not.toBeNull();
|
|
});
|
|
|
|
it("should hide the popover when pressing the escape key", () => {
|
|
const onClose = jest.fn();
|
|
|
|
const wrapper = render(
|
|
<Popover isOpen onOpenChange={(isOpen) => (!isOpen ? onClose() : undefined)}>
|
|
<PopoverTrigger>
|
|
<button>Open popover</button>
|
|
</PopoverTrigger>
|
|
<PopoverContent data-testid="content-test">
|
|
<p>This is the content of the popover.</p>
|
|
</PopoverContent>
|
|
</Popover>,
|
|
);
|
|
|
|
const content = wrapper.getByTestId("content-test");
|
|
|
|
fireEvent.keyDown(content, {key: "Escape"});
|
|
expect(onClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("should still hide the popover when pressing the escape key ", () => {
|
|
const onClose = jest.fn();
|
|
|
|
const wrapper = render(
|
|
<Popover isOpen onClose={onClose}>
|
|
<PopoverTrigger>
|
|
<button>Open popover</button>
|
|
</PopoverTrigger>
|
|
<PopoverContent data-testid="content-test">
|
|
<p>This is the content of the popover.</p>
|
|
</PopoverContent>
|
|
</Popover>,
|
|
);
|
|
|
|
const content = wrapper.getByTestId("content-test");
|
|
|
|
fireEvent.keyDown(content, {key: "Escape"});
|
|
expect(onClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("should hide the popover on blur (shouldCloseOnBlur=true)", () => {
|
|
const onClose = jest.fn();
|
|
|
|
const wrapper = render(
|
|
<Popover isOpen shouldCloseOnBlur onClose={onClose}>
|
|
<PopoverTrigger>
|
|
<button>Open popover</button>
|
|
</PopoverTrigger>
|
|
<PopoverContent data-testid="content-test">
|
|
<p>This is the content of the popover.</p>
|
|
</PopoverContent>
|
|
</Popover>,
|
|
);
|
|
|
|
const content = wrapper.getByTestId("content-test");
|
|
|
|
act(() => {
|
|
content.blur();
|
|
});
|
|
|
|
expect(onClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("should work with NextUI button", () => {
|
|
const onClose = jest.fn();
|
|
|
|
const wrapper = render(
|
|
<Popover onClose={onClose}>
|
|
<PopoverTrigger>
|
|
<Button disableRipple 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(onClose).toHaveBeenCalledTimes(0);
|
|
|
|
// close popover
|
|
act(() => {
|
|
trigger.click();
|
|
});
|
|
|
|
expect(onClose).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("should close listbox by clicking another popover", async () => {
|
|
const wrapper = render(
|
|
<>
|
|
<Popover>
|
|
<PopoverTrigger>
|
|
<button data-testid="popover">Open popover</button>
|
|
</PopoverTrigger>
|
|
<PopoverContent>
|
|
<p>This is the content of the popover.</p>
|
|
</PopoverContent>
|
|
</Popover>
|
|
<Popover>
|
|
<PopoverTrigger>
|
|
<button data-testid="popover2">Open popover</button>
|
|
</PopoverTrigger>
|
|
<PopoverContent>
|
|
<p>This is the content of the popover.</p>
|
|
</PopoverContent>
|
|
</Popover>
|
|
</>,
|
|
);
|
|
|
|
const popover = wrapper.getByTestId("popover");
|
|
|
|
const popover2 = wrapper.getByTestId("popover2");
|
|
|
|
expect(popover).not.toBeNull();
|
|
|
|
expect(popover2).not.toBeNull();
|
|
|
|
// open the popover by clicking popover in the first popover
|
|
await act(async () => {
|
|
await userEvent.click(popover);
|
|
});
|
|
|
|
// assert that the first popover is open
|
|
expect(popover).toHaveAttribute("aria-expanded", "true");
|
|
|
|
// assert that the second popover is close
|
|
expect(popover2).toHaveAttribute("aria-expanded", "false");
|
|
|
|
// close the popover by clicking the second popover
|
|
await act(async () => {
|
|
await userEvent.click(popover2);
|
|
});
|
|
|
|
// assert that the first popover is closed
|
|
expect(popover).toHaveAttribute("aria-expanded", "false");
|
|
|
|
// assert that the second popover is open
|
|
expect(popover2).toHaveAttribute("aria-expanded", "true");
|
|
});
|
|
});
|