@crossed/ui
Version:
A universal & performant styling library for React Native, Next.js & React
219 lines (218 loc) • 9.83 kB
JavaScript
import { jsx, jsxs } from "react/jsx-runtime";
import { render } from "@crossed/test";
import { DropDownMenu } from "../index";
import { Popover, useFloatingContext } from "../../overlay";
import { MenuList } from "../MenuList";
import { Divider } from "../../layout/Divider";
import { useMedia } from "../../useMedia";
import { Text } from "../../typography";
jest.mock("../../overlay", () => ({
Popover: Object.assign(
jest.fn(({ children }) => children),
{
Trigger: jest.fn(({ children }) => children),
Content: jest.fn(({ children }) => children)
}
),
useFloatingContext: jest.fn()
}));
jest.mock("../MenuList", () => ({
MenuList: Object.assign(
jest.fn(({ children }) => children),
{
Item: jest.fn(({ children }) => children),
Label: jest.fn(({ children }) => children),
Title: jest.fn(({ children }) => children)
}
)
}));
jest.mock("../../layout/Divider", () => ({
Divider: jest.fn(() => null)
}));
jest.mock("../../useMedia", () => ({
useMedia: jest.fn()
}));
const PopoverMocked = jest.mocked(Popover);
const MenuListMocked = jest.mocked(MenuList);
const useFloatingContextMocked = jest.mocked(useFloatingContext);
const useMediaMocked = jest.mocked(useMedia);
const DividerMocked = jest.mocked(Divider);
const mockUseMedia = (md) => {
useMediaMocked.mockReturnValue({
md,
sm: false,
lg: false,
xl: false
});
};
const mockFloatingContext = (onClose = jest.fn()) => {
useFloatingContextMocked.mockReturnValue({
onClose,
open: true,
onOpen: jest.fn()
});
};
describe("DropDownMenu", () => {
beforeEach(() => {
mockUseMedia(true);
mockFloatingContext();
});
afterEach(() => {
jest.clearAllMocks();
});
test("renders with default props", () => {
render(
/* @__PURE__ */ jsxs(DropDownMenu, { children: [
/* @__PURE__ */ jsx(DropDownMenu.Trigger, { children: /* @__PURE__ */ jsx(Text, { children: "Open Menu" }) }),
/* @__PURE__ */ jsx(DropDownMenu.Content, { children: /* @__PURE__ */ jsx(DropDownMenu.Item, { children: /* @__PURE__ */ jsx(DropDownMenu.Label, { children: "Item 1" }) }) })
] })
);
const call = PopoverMocked.mock.calls[0][0];
expect(call).toHaveProperty("placement", "bottom-end");
expect(call).toHaveProperty("triggerStrategy", "onPress");
expect(call).toHaveProperty("children");
});
test("accepts custom placement", () => {
render(
/* @__PURE__ */ jsxs(DropDownMenu, { placement: "top-start", children: [
/* @__PURE__ */ jsx(DropDownMenu.Trigger, { children: /* @__PURE__ */ jsx(Text, { children: "Open Menu" }) }),
/* @__PURE__ */ jsx(DropDownMenu.Content, { children: /* @__PURE__ */ jsx(DropDownMenu.Item, { children: /* @__PURE__ */ jsx(DropDownMenu.Label, { children: "Item 1" }) }) })
] })
);
const call = PopoverMocked.mock.calls[0][0];
expect(call).toHaveProperty("placement", "top-start");
});
test("accepts custom triggerStrategy", () => {
render(
/* @__PURE__ */ jsxs(DropDownMenu, { triggerStrategy: "onPointerEnter", children: [
/* @__PURE__ */ jsx(DropDownMenu.Trigger, { children: /* @__PURE__ */ jsx(Text, { children: "Open Menu" }) }),
/* @__PURE__ */ jsx(DropDownMenu.Content, { children: /* @__PURE__ */ jsx(DropDownMenu.Item, { children: /* @__PURE__ */ jsx(DropDownMenu.Label, { children: "Item 1" }) }) })
] })
);
const call = PopoverMocked.mock.calls[0][0];
expect(call).toHaveProperty("triggerStrategy", "onPointerEnter");
});
test("forwards additional props to Popover", () => {
render(
/* @__PURE__ */ jsxs(DropDownMenu, { offsetValue: 15, children: [
/* @__PURE__ */ jsx(DropDownMenu.Trigger, { children: /* @__PURE__ */ jsx(Text, { children: "Open Menu" }) }),
/* @__PURE__ */ jsx(DropDownMenu.Content, { children: /* @__PURE__ */ jsx(DropDownMenu.Item, { children: /* @__PURE__ */ jsx(DropDownMenu.Label, { children: "Item 1" }) }) })
] })
);
const call = PopoverMocked.mock.calls[0][0];
expect(call).toHaveProperty("offsetValue", 15);
});
test("renders all static components", () => {
expect(DropDownMenu.Trigger).toBeDefined();
expect(DropDownMenu.Content).toBeDefined();
expect(DropDownMenu.Item).toBeDefined();
expect(DropDownMenu.Label).toBeDefined();
expect(DropDownMenu.Title).toBeDefined();
expect(DropDownMenu.Divider).toBeDefined();
});
test("Content renders MenuList with bordered=true on desktop", () => {
mockUseMedia(true);
MenuListMocked.mockClear();
render(
/* @__PURE__ */ jsxs(DropDownMenu, { children: [
/* @__PURE__ */ jsx(DropDownMenu.Trigger, { children: /* @__PURE__ */ jsx(Text, { children: "Open Menu" }) }),
/* @__PURE__ */ jsx(DropDownMenu.Content, { children: /* @__PURE__ */ jsx(DropDownMenu.Item, { children: /* @__PURE__ */ jsx(DropDownMenu.Label, { children: "Item 1" }) }) })
] })
);
const menuListCall = MenuListMocked.mock.calls[0][0];
expect(menuListCall).toHaveProperty("bordered", true);
});
test("Content renders MenuList with bordered=false on mobile", () => {
mockUseMedia(false);
MenuListMocked.mockClear();
render(
/* @__PURE__ */ jsxs(DropDownMenu, { children: [
/* @__PURE__ */ jsx(DropDownMenu.Trigger, { children: /* @__PURE__ */ jsx(Text, { children: "Open Menu" }) }),
/* @__PURE__ */ jsx(DropDownMenu.Content, { children: /* @__PURE__ */ jsx(DropDownMenu.Item, { children: /* @__PURE__ */ jsx(DropDownMenu.Label, { children: "Item 1" }) }) })
] })
);
const menuListCall = MenuListMocked.mock.calls[0][0];
expect(menuListCall).toHaveProperty("bordered", false);
});
test("Item closes popover on press", () => {
const onClose = jest.fn();
mockFloatingContext(onClose);
const MenuListItemMocked = jest.mocked(MenuList.Item);
render(
/* @__PURE__ */ jsxs(DropDownMenu, { children: [
/* @__PURE__ */ jsx(DropDownMenu.Trigger, { children: /* @__PURE__ */ jsx(Text, { children: "Open Menu" }) }),
/* @__PURE__ */ jsx(DropDownMenu.Content, { children: /* @__PURE__ */ jsx(DropDownMenu.Item, { onPress: () => {
}, children: /* @__PURE__ */ jsx(DropDownMenu.Label, { children: "Item 1" }) }) })
] })
);
const itemCall = MenuListItemMocked.mock.calls[0][0];
expect(itemCall).toHaveProperty("onPress");
if ("onPress" in itemCall && typeof itemCall.onPress === "function") {
itemCall.onPress({});
}
expect(onClose).toHaveBeenCalledTimes(1);
});
test("Item composes custom onPress with onClose", () => {
const onClose = jest.fn();
const customOnPress = jest.fn();
mockFloatingContext(onClose);
const MenuListItemMocked = jest.mocked(MenuList.Item);
render(
/* @__PURE__ */ jsxs(DropDownMenu, { children: [
/* @__PURE__ */ jsx(DropDownMenu.Trigger, { children: /* @__PURE__ */ jsx(Text, { children: "Open Menu" }) }),
/* @__PURE__ */ jsx(DropDownMenu.Content, { children: /* @__PURE__ */ jsx(DropDownMenu.Item, { onPress: customOnPress, children: /* @__PURE__ */ jsx(DropDownMenu.Label, { children: "Item 1" }) }) })
] })
);
const itemCall = MenuListItemMocked.mock.calls[0][0];
if ("onPress" in itemCall && typeof itemCall.onPress === "function") {
itemCall.onPress({});
}
expect(customOnPress).toHaveBeenCalledTimes(1);
expect(onClose).toHaveBeenCalledTimes(1);
});
test("Label renders MenuList.Label", () => {
const MenuListLabelMocked = jest.mocked(MenuList.Label);
render(
/* @__PURE__ */ jsxs(DropDownMenu, { children: [
/* @__PURE__ */ jsx(DropDownMenu.Trigger, { children: /* @__PURE__ */ jsx(Text, { children: "Open Menu" }) }),
/* @__PURE__ */ jsx(DropDownMenu.Content, { children: /* @__PURE__ */ jsx(DropDownMenu.Item, { children: /* @__PURE__ */ jsx(DropDownMenu.Label, { children: "Item 1" }) }) })
] })
);
expect(MenuListLabelMocked).toHaveBeenCalled();
});
test("Title renders MenuList.Title", () => {
const MenuListTitleMocked = jest.mocked(MenuList.Title);
render(
/* @__PURE__ */ jsxs(DropDownMenu, { children: [
/* @__PURE__ */ jsx(DropDownMenu.Trigger, { children: /* @__PURE__ */ jsx(Text, { children: "Open Menu" }) }),
/* @__PURE__ */ jsx(DropDownMenu.Content, { children: /* @__PURE__ */ jsx(DropDownMenu.Title, { children: "Menu Title" }) })
] })
);
expect(MenuListTitleMocked).toHaveBeenCalled();
});
test("Divider renders Divider component", () => {
render(
/* @__PURE__ */ jsxs(DropDownMenu, { children: [
/* @__PURE__ */ jsx(DropDownMenu.Trigger, { children: /* @__PURE__ */ jsx(Text, { children: "Open Menu" }) }),
/* @__PURE__ */ jsxs(DropDownMenu.Content, { children: [
/* @__PURE__ */ jsx(DropDownMenu.Item, { children: /* @__PURE__ */ jsx(DropDownMenu.Label, { children: "Item 1" }) }),
/* @__PURE__ */ jsx(DropDownMenu.Divider, {}),
/* @__PURE__ */ jsx(DropDownMenu.Item, { children: /* @__PURE__ */ jsx(DropDownMenu.Label, { children: "Item 2" }) })
] })
] })
);
expect(DividerMocked).toHaveBeenCalled();
});
test("Divider forwards props", () => {
DividerMocked.mockClear();
render(
/* @__PURE__ */ jsxs(DropDownMenu, { children: [
/* @__PURE__ */ jsx(DropDownMenu.Trigger, { children: /* @__PURE__ */ jsx(Text, { children: "Open Menu" }) }),
/* @__PURE__ */ jsx(DropDownMenu.Content, { children: /* @__PURE__ */ jsx(DropDownMenu.Divider, { direction: "vertical" }) })
] })
);
const dividerCall = DividerMocked.mock.calls[0][0];
expect(dividerCall).toHaveProperty("direction", "vertical");
});
});
//# sourceMappingURL=DropDownMenu.spec.js.map