mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
* refactor(input): input ref test (#2613) * refactor(input): remove duplicate test * refactor(input): remove unncessary waitFor * fix(radio): isRequired & missing warning message in Form (#2597) * fix(radio): avoid overriding required props * fix(radio): merge with domRef * feat(changeset): fixed missing required props and validationMessage * fix(radio): unnecessary mergeRefs * Calendar component 📅 (#2456) * feat(calendar): initial structure * feat(calendar): calendar structure completed, styles in progress * chore(calendar): dark colors adjusted * feat(calendar): styles improved, variants added, animations added with framer motion * chore(calendar): animation changed, shadow improved * chore(calendar): disableAnimation support added as well as weekDays format * feat(calendar): more stories added * chore(calendar): refactor calendar cell styling * feat(calendar): create calendar function added to the root provider * feat(calendar): invalid state and error message added * feat(calendar): calendar picker added, provider modified * feat(root): object.values deps replaced by new func, intersection hoook added, types version unified * feat(calendar): calendar pickers in progress * feat(calendar): calendar pickers added * fix(calendar): year label formatting * chore(calendar): add layout parameter to Calendar stories * feat(calendar): pickers completed, context added * feat(calendar): visibleMonths supported, warnings fixed, tests added * chore(root): changeset * chore(calendar): add topContent and bottomContent props to calendar * feat(calendar): add @nextui-org/radio package and update calendar component * refactor: assigned type(DateValue) to focusedDate(ControlledFocusedVaue) (#2637) Co-authored-by: shrinidhi.upadhyaya <shrinidhi.upadhyaya@stud.uni-bamberg.de> * Range Calendar 📆 (#2634) * feat(calendar): range calendar added, calendar and context adapted * feat(calendar): range calendar stories added * chore(calendar): range calendar tests added * fix(calendar): update calendar styles to adjust to dynamic width * Date Input 🗓️ (#2641) * feat(date-picker): date field component initialized * chore(date-picker): date field renamed to date-input * feat(date-picker): date input completed * chore(date-input): commented code removed * feat(avatar): support slots in AvatarGroup (#2669) * feat: rename newPost to new (#2665) * fix(avatar): spread getAvatarGroupCountProps in avatar count * feat(avatar): support slots in avatarGroup * feat(avatar): support classNames and add getAvatarGroupCountProps * feat(docs): add classNames to avatar group * feat(avatar): add CustomSlots in avatar group * feat(changeset): support slots in avatar group --------- Co-authored-by: winches <96854855+winchesHe@users.noreply.github.com> * Date Picker Component 🗓️ (#2652) * feat(date-picker): first iteration * chore(date-picker): update date-picker README.md with improved description * feat(date-picker): code organized, integration done * fix(date-picker): min and max value + styles * fix(date-picker): popover offset adn calendar styles * feat(date-picker): stories added * fix(date-picker): calendar width properly handled * feat(date-picker): styles simplified * chore(date-picker): almost all test passing * fix(date-picker): test and styles * chore(date-picker): calendar popover tests added * fix(date-picker): props to be passed to the date-input * TimeInput Component 🕒 (#2672) * feat(time-input): time input added with some stories, tests and date-picker integration missing * feat(time-input): tests added, date-picker integration added, missing stories added * chore(react): missing packages added * chore(time-input): fix stories names * fix(time-input): time value type * fix: date-picker visibleMonth width does not get widen enough (#2703) * DateRangePicker Component 🗓️ (#2682) * chore(date-range-picker): in progress * chore(date-range-picker): in progress * feat(date-input): components separated into multiple pieces to be able to implement the date range picker * feat(date-range-picker): first version of it working * chore(date-picker): hyphen symbol changed * feat(date-range-picker): stories done * fix(range-calendar): styles * docs: Calendar & RangeCalendar (#2686) * feat(docs): add calendar in routes.json * feat(docs): refresh search-meta.json * feat(docs): add calendar examples * feat(docs): calendar content * feat(deps): add @internationalized/date * refactor(docs): remove div wrapper * feat(docs): add calendar doc * fix(docs): calendar presets * fix(docs): preset styles * chore(docs): remove calendar iframe examples * refactor(docs): discard iframe in calendar doc * fix(docs): incorrect DateValue import * feat(docs): include @internationalized/date in live demo scope * feat(docs): add presets description * chore(docs): update search-meta.json * fix(docs): remove DateValue * feat(docs): include reactAriaI18n in react live demo scope * fix(docs): presets import issue * chore(docs): update search-meta.json * feat(docs): add api reference for nextui provider * fix(calendar): ixExpanded typo * feat(docs): add missing props & event * chore(docs): update search-meta.json * chore(docs): update route keywords * chore(docs): revise value style add defaultFocusedValue * chore(docs): remove padding and revise gap * feat(docs): range calendar * chore(docs): update search-meta.json * feat(docs): add reactAriaHook * fix(docs): incorrect component and add storybook and reactAriaHook * fix(docs): incorrect import path * chore(docs): reorder range calendar position in sidebar * chore(Docs): remove custom styles & implementation * chore(docs): remove last item from accessibility * chore(docs): onValueChange -> onChange * feat(docs): add ts example for range calendar * chore(docs): remove unwanted content in range calendar * feat(docs): add ts examples for calendar * chore(docs): update import path * chore(docs): update import path * chore(docs): styles adjusted, routes updated --------- Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> * docs: TimeInput (#2698) * feat(docs): add time input to routes.json * feat(deps): add @internationalized/date * feat(docs): add @internationalized/date and @react-aria/i18n to code demo scopes * feat(docs): time input contetnt * chore(docs): revise time input examples * feat(docs): time input content * chore(time-input): update description * feat(docs): add ts examples in time-input * chore(docs): revise TimeValue import --------- Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> * chore(date-picker): exports updated * docs: DatePicker (#2700) * docs: created the doc for datepicker and its examples * docs: regenerate search-meta.json * fix: reverted the unncessary change to Input component * fix: fixed the component-link for date-picker * fix: fixed the component-link for date-picker * fix: added variants section to the doc * fix: made adjustment to the explanations for the props of DatePicker comp --------- Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> * doc: DateInput (#2711) * docs: created base examples and the document * chore: created search-meta and follow-up fix for each date-input example cases * fix: fixed some example components styles * fix(docs): updated routes.json * fix(docs): fixed typo in the docs * fix: fixed the component-link for date-input * fix: fixed the component-link for date-input * fix: label-placements example flex style adjustment * fix: added variants section to the doc --------- Co-authored-by: HaRuki Kuriwada <haruki.kuriwada@hennge.com> Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> * refactor(theme): units removed, tailwind-variants upgraded (#2713) * fix(theme): units replaced by spacing * fix(select): positioning the label if a description is used (#2553) Co-authored-by: Poli Sour <polisour.work@gmail.com> * Upgrade to new react aria version (#2561) * chore(root): pkg upgraded * fix: type error * fix: build error * chore: update packages from a~d * chore: update packages from i~r * chore: update packages from s~u * chore: update core, hooks, and utilities packages * feat: add support radio group validationBehavior props * fix: validationBehavior default to native * chore: add validationBehavior props in RadioGroup Stories * fix: handling of errorMessage * chore: add support validationBehavior autocomplete * chore: partial support for validation of select * chore: add support validationBehavior checkbox * chore: change validationBehavior default to native * Merge branch 'v.2.3.0' into feat/upgrade-react-aria * fix: validation logic * fix: add default value for autocomplete * chore: add example using error message function * chore: fixed error displayed in storybook * chore: omit validationBehavior from component props * chore: update docs and storybook on validate * fix: pnpm-lock version --------- Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> * fix(core): build and date input / time input apis * chore(date-picker): omit validation behavior * chore(docs): add missing props to calendar and range calendar * docs: add nextui-cli page (#2714) * docs: add nextui-cli page * docs: update search meta * docs: typo * docs: typo * docs: typo * feat(docs): cli docs done --------- Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> * chore(docs): add cli commands to installation docs * fix(checkbox): prettier * fix(docs): incorrect cli api references link * doc: DateRangePicker (#2712) * chore: created base for date-range-picker doc * fix: added follow-up story examples to the doc * fix: fixed bugs happening on the doc * fix: fixed bugs happening on the doc * fix(docs): incorrect file path and revise title * fix: component examples style fixes * fix: component presets typo fix * refactor(core): date range picker docs completed, standaline date picker field fixed --------- Co-authored-by: HaRuki Kuriwada <haruki.kuriwada@hennge.com> Co-authored-by: աɨռɢӄաօռɢ <wingkwong.code@gmail.com> Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> * fix: only two keyframes currently supported with spring and inertia animations (#2596) * chore(deps): bump framer-motion * feat(changeset): fixed framer motion issue * chore(changeset): revise changeset message * chore(deps): update pnpm-lock.yaml * fix: react hook form issue (#2603) * fix(input): pass domRef?.current?.value to controlled state * fix(input): pass domRef?.current?.value to useTextField instead * fix(checkbox): handle RHF case * fix(checkbox): add missing isSelected case * chore(checkbox): update ref type * chore(deps): add @nextui-org/use-safe-layout-effect * chore(deps): update pnpm-lock.yaml * chore(deps): update pnpm-lock.yaml * fix(select): handle RHF case * chore(deps): add @nextui-org/use-safe-layout-effect to select * fix(autocomplete): handle RHF case * chore(deps): add @nextui-org/use-safe-layout-effect to autocomplete * refactor(components): revise comments * feat(changeset): react-hook-form uncontrolled components * chore(deps): pnpm-lock.yaml * fix(input): domRef.current.value has higher precedence * fix(checkbox): set isChecked based on input ref checked * feat(components): tabs component add tabPosition prop (#2398) * feat(components): tabs component add tabPosition prop * fix: review problem change * test: add tabs position vertical test * docs: update changeset * fix(tabs): optimize return of tabs * fix(tabs): rename orientation to placement * fix(tabs): optimize description * chore(docs): routes * fix: isReadOnly in Autocomplete MDX (#2444) * feat(autocomplete): add isReadOnly example * fix(autocomplete): isReadOnly logic in Autocomplete * feat(root): add changeset - fixed isReadOnly logic in Autocomplete * chore(autocomplete component) isReadOnly property demo isReadOnly property demo in website MDX for autocomplete component. * Update apps/docs/content/docs/components/autocomplete.mdx Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> --------- Co-authored-by: աɨռɢӄաօռɢ <wingkwong.code@gmail.com> Co-authored-by: Alpha <116849110+alpha-xek@users.noreply.github.com> Co-authored-by: Junior Garcia <jrgarciadev@gmail.com> * fix(select): only trigger setSelectedKeys when domRef.current.value is true (#2722) * chore(docs): blog changes (#2724) * chore(docs): blog changes * feat(docs): blog improved * chore(blog): draft param added * chore: version changeset added * feat(blog): v2.3.0 almost done * chore(docs): tailwind colors updated, calendar overflow fixed * chore(blog): add presets demo * fix(calendar): overflow on windows * chore(docs): improve popover placements demo * fix(autocomplete): set shouldUseVirtualFocus to false in getListboxProps (#2731) * chore(blog): add cotributors * chore(blog): draft --------- Co-authored-by: աӄա <wingkwong.code@gmail.com> Co-authored-by: Shrinidhi Upadhyaya <shrinidhiupadhyaya1195@gmail.com> Co-authored-by: shrinidhi.upadhyaya <shrinidhi.upadhyaya@stud.uni-bamberg.de> Co-authored-by: winches <96854855+winchesHe@users.noreply.github.com> Co-authored-by: HaRuki <soccer_haruki15@me.com> Co-authored-by: HaRuki Kuriwada <haruki.kuriwada@hennge.com> Co-authored-by: Poli Sour <57824881+novsource@users.noreply.github.com> Co-authored-by: Poli Sour <polisour.work@gmail.com> Co-authored-by: Ryo Matsukawa <76232929+ryo-manba@users.noreply.github.com> Co-authored-by: winches <329487092@qq.com> Co-authored-by: Alpha Xek <116849110+alphaxek@users.noreply.github.com> Co-authored-by: Alpha <116849110+alpha-xek@users.noreply.github.com>
322 lines
8.9 KiB
TypeScript
322 lines
8.9 KiB
TypeScript
import * as React from "react";
|
|
import {act, render} from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import {focus} from "@nextui-org/test-utils";
|
|
|
|
import {Tabs, Tab, TabsProps} from "../src";
|
|
|
|
type Item = {
|
|
id: string;
|
|
label: string;
|
|
content?: React.ReactNode;
|
|
};
|
|
|
|
let tabs: Item[] = [
|
|
{
|
|
id: "item1",
|
|
label: "Item1 ",
|
|
content: "Content 1",
|
|
},
|
|
{
|
|
id: "item2",
|
|
label: "Item 2",
|
|
content: "Content 2",
|
|
},
|
|
{
|
|
id: "item3",
|
|
label: "Item 3",
|
|
content: "Content 3",
|
|
},
|
|
];
|
|
|
|
function getPlacementTemplate(position: TabsProps["placement"]) {
|
|
return (
|
|
<Tabs aria-label="Tabs static test" data-testid="tabWrapper" placement={position}>
|
|
<Tab key="item1" title="Item 1">
|
|
<div>Content 1</div>
|
|
</Tab>
|
|
<Tab key="item2" title="Item 2">
|
|
<div>Content 2</div>
|
|
</Tab>
|
|
<Tab key="item3" title="Item 3">
|
|
<div>Content 3</div>
|
|
</Tab>
|
|
</Tabs>
|
|
);
|
|
}
|
|
|
|
// 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">
|
|
<Tab key="item1" title="Item 1">
|
|
<div>Content 1</div>
|
|
</Tab>
|
|
<Tab key="item2" title="Item 2">
|
|
<div>Content 2</div>
|
|
</Tab>
|
|
<Tab key="item3" title="Item 3">
|
|
<div>Content 3</div>
|
|
</Tab>
|
|
</Tabs>,
|
|
);
|
|
|
|
expect(() => wrapper.unmount()).not.toThrow();
|
|
|
|
expect(spy).toBeCalledTimes(0);
|
|
});
|
|
|
|
it("should render correctly (dynamic)", () => {
|
|
const wrapper = render(
|
|
<Tabs aria-label="Tabs static test" items={tabs}>
|
|
{(item) => (
|
|
<Tab key={item.id} title={item.label}>
|
|
<div>{item.content}</div>
|
|
</Tab>
|
|
)}
|
|
</Tabs>,
|
|
);
|
|
|
|
expect(() => wrapper.unmount()).not.toThrow();
|
|
});
|
|
|
|
it("ref should be forwarded", () => {
|
|
const ref = React.createRef<HTMLDivElement>();
|
|
|
|
render(
|
|
<Tabs ref={ref} aria-label="Tabs static test">
|
|
<Tab key="item1" title="Item 1">
|
|
<div>Content 1</div>
|
|
</Tab>
|
|
<Tab key="item2" title="Item 2">
|
|
<div>Content 2</div>
|
|
</Tab>
|
|
<Tab key="item3" title="Item 3">
|
|
<div>Content 3</div>
|
|
</Tab>
|
|
</Tabs>,
|
|
);
|
|
expect(ref.current).not.toBeNull();
|
|
});
|
|
|
|
test("should select the correct tab with keyboard navigation", async () => {
|
|
const wrapper = render(
|
|
<Tabs aria-label="Tabs static test">
|
|
<Tab key="item1" title="Item 1">
|
|
<div>Content 1</div>
|
|
</Tab>
|
|
<Tab key="item2" title="Item 2">
|
|
<div>Content 2</div>
|
|
</Tab>
|
|
<Tab key="item3" title="Item 3">
|
|
<div>Content 3</div>
|
|
</Tab>
|
|
</Tabs>,
|
|
);
|
|
|
|
const tab1 = wrapper.getByRole("tab", {name: "Item 1"});
|
|
const tab2 = wrapper.getByRole("tab", {name: "Item 2"});
|
|
const tab3 = wrapper.getByRole("tab", {name: "Item 3"});
|
|
|
|
expect(tab1).toHaveAttribute("aria-selected", "true");
|
|
expect(tab2).toHaveAttribute("aria-selected", "false");
|
|
expect(tab3).toHaveAttribute("aria-selected", "false");
|
|
|
|
act(() => {
|
|
focus(tab1);
|
|
});
|
|
|
|
await act(async () => {
|
|
await userEvent.keyboard("[ArrowRight]");
|
|
});
|
|
|
|
expect(tab1).toHaveAttribute("aria-selected", "false");
|
|
expect(tab2).toHaveAttribute("aria-selected", "true");
|
|
expect(tab3).toHaveAttribute("aria-selected", "false");
|
|
|
|
await act(async () => {
|
|
await userEvent.keyboard("[ArrowRight]");
|
|
});
|
|
|
|
expect(tab1).toHaveAttribute("aria-selected", "false");
|
|
expect(tab2).toHaveAttribute("aria-selected", "false");
|
|
expect(tab3).toHaveAttribute("aria-selected", "true");
|
|
|
|
await act(async () => {
|
|
await userEvent.keyboard("[ArrowRight]");
|
|
});
|
|
|
|
expect(tab1).toHaveAttribute("aria-selected", "true");
|
|
expect(tab2).toHaveAttribute("aria-selected", "false");
|
|
expect(tab3).toHaveAttribute("aria-selected", "false");
|
|
});
|
|
|
|
test("should focus the correct tab with manual keyboard navigation", async () => {
|
|
const wrapper = render(
|
|
<Tabs aria-label="Tabs static test" keyboardActivation="manual">
|
|
<Tab key="item1" data-testid="item1" title="Item 1">
|
|
<div>Content 1</div>
|
|
</Tab>
|
|
<Tab key="item2" data-testid="item2" title="Item 2">
|
|
<div>Content 2</div>
|
|
</Tab>
|
|
<Tab key="item3" data-testid="item3" title="Item 3">
|
|
<div>Content 3</div>
|
|
</Tab>
|
|
</Tabs>,
|
|
);
|
|
|
|
const tab1 = wrapper.getByTestId("item1");
|
|
const tab2 = wrapper.getByTestId("item2");
|
|
const tab3 = wrapper.getByTestId("item3");
|
|
|
|
expect(tab1).toHaveAttribute("aria-selected", "true");
|
|
expect(tab2).toHaveAttribute("aria-selected", "false");
|
|
expect(tab3).toHaveAttribute("aria-selected", "false");
|
|
|
|
act(() => {
|
|
focus(tab1);
|
|
});
|
|
|
|
await act(async () => {
|
|
await userEvent.keyboard("[ArrowRight]");
|
|
});
|
|
|
|
expect(tab2).toHaveFocus();
|
|
|
|
await act(async () => {
|
|
await userEvent.keyboard("[ArrowRight]");
|
|
});
|
|
|
|
expect(tab3).toHaveFocus();
|
|
|
|
await act(async () => {
|
|
await userEvent.keyboard("[ArrowLeft]");
|
|
});
|
|
|
|
expect(tab2).toHaveFocus();
|
|
|
|
expect(tab1).toHaveAttribute("aria-selected", "true");
|
|
expect(tab2).toHaveAttribute("aria-selected", "false");
|
|
expect(tab3).toHaveAttribute("aria-selected", "false");
|
|
});
|
|
|
|
it("it should work with defaultSelectedKey", () => {
|
|
const wrapper = render(
|
|
<Tabs aria-label="Tabs static test" defaultSelectedKey="item2">
|
|
<Tab key="item1" title="Item 1">
|
|
<div>Content 1</div>
|
|
</Tab>
|
|
<Tab key="item2" data-testid="item2" title="Item 2">
|
|
<div>Content 2</div>
|
|
</Tab>
|
|
<Tab key="item3" title="Item 3">
|
|
<div>Content 3</div>
|
|
</Tab>
|
|
</Tabs>,
|
|
);
|
|
|
|
const tab2 = wrapper.getByTestId("item2");
|
|
|
|
expect(tab2).toHaveAttribute("aria-selected", "true");
|
|
});
|
|
|
|
it("should not select a tab when disabled", async () => {
|
|
const wrapper = render(
|
|
<Tabs aria-label="Tabs static test" disabledKeys={["item2"]}>
|
|
<Tab key="item1" title="Item 1">
|
|
<div>Content 1</div>
|
|
</Tab>
|
|
<Tab key="item2" data-testid="item2" title="Item 2">
|
|
<div>Content 2</div>
|
|
</Tab>
|
|
<Tab key="item3" title="Item 3">
|
|
<div>Content 3</div>
|
|
</Tab>
|
|
</Tabs>,
|
|
);
|
|
|
|
const tab2 = wrapper.getByTestId("item2");
|
|
|
|
await act(async () => {
|
|
await userEvent.click(tab2);
|
|
});
|
|
|
|
expect(tab2).toHaveAttribute("aria-selected", "false");
|
|
});
|
|
|
|
it("should change the position of the tabs", () => {
|
|
const wrapper = render(getPlacementTemplate("top"));
|
|
|
|
const tabWrapper = wrapper.getByTestId("tabWrapper").parentNode;
|
|
|
|
expect(tabWrapper).toHaveAttribute("data-placement", "top");
|
|
expect(tabWrapper).toHaveAttribute("data-vertical", "horizontal");
|
|
|
|
// Test bottom position
|
|
wrapper.rerender(getPlacementTemplate("bottom"));
|
|
|
|
expect(tabWrapper).toHaveAttribute("data-placement", "bottom");
|
|
expect(tabWrapper).toHaveAttribute("data-vertical", "horizontal");
|
|
|
|
// Test start position
|
|
wrapper.rerender(getPlacementTemplate("start"));
|
|
|
|
expect(tabWrapper).toHaveAttribute("data-placement", "start");
|
|
expect(tabWrapper).toHaveAttribute("data-vertical", "vertical");
|
|
|
|
// Test end position
|
|
wrapper.rerender(getPlacementTemplate("end"));
|
|
|
|
expect(tabWrapper).toHaveAttribute("data-placement", "end");
|
|
expect(tabWrapper).toHaveAttribute("data-vertical", "vertical");
|
|
});
|
|
|
|
it("should change the orientation of the tabs", () => {
|
|
const wrapper = render(
|
|
<Tabs isVertical aria-label="Tabs static test" data-testid="tabWrapper">
|
|
<Tab key="item1" title="Item 1">
|
|
<div>Content 1</div>
|
|
</Tab>
|
|
<Tab key="item2" title="Item 2">
|
|
<div>Content 2</div>
|
|
</Tab>
|
|
<Tab key="item3" title="Item 3">
|
|
<div>Content 3</div>
|
|
</Tab>
|
|
</Tabs>,
|
|
);
|
|
|
|
const tabWrapper = wrapper.getByTestId("tabWrapper").parentNode;
|
|
|
|
expect(tabWrapper).toHaveAttribute("data-placement", "start");
|
|
expect(tabWrapper).toHaveAttribute("data-vertical", "vertical");
|
|
|
|
// Test horizontal orientation
|
|
wrapper.rerender(
|
|
<Tabs aria-label="Tabs static test" data-testid="tabWrapper" isVertical={false}>
|
|
<Tab key="item1" title="Item 1">
|
|
<div>Content 1</div>
|
|
</Tab>
|
|
<Tab key="item2" title="Item 2">
|
|
<div>Content 2</div>
|
|
</Tab>
|
|
<Tab key="item3" title="Item 3">
|
|
<div>Content 3</div>
|
|
</Tab>
|
|
</Tabs>,
|
|
);
|
|
|
|
expect(tabWrapper).toHaveAttribute("data-placement", "top");
|
|
expect(tabWrapper).toHaveAttribute("data-vertical", "horizontal");
|
|
});
|
|
});
|