carbon-components-svelte/tests/OverflowMenu/OverflowMenu.test.ts

130 lines
4.4 KiB
TypeScript

import { render, screen } from "@testing-library/svelte";
import { user } from "../setup-tests";
import OverflowMenu from "./OverflowMenu.test.svelte";
describe("OverflowMenu", () => {
it("renders and functions correctly", async () => {
render(OverflowMenu);
const menuButton = screen.getByRole("button");
expect(menuButton).toHaveAttribute("aria-haspopup", "true");
expect(menuButton).toHaveAttribute("aria-expanded", "false");
await user.click(menuButton);
expect(menuButton).toHaveAttribute("aria-expanded", "true");
const menuItems = screen.getAllByRole("menuitem");
expect(menuItems).toHaveLength(3);
expect(menuItems[0]).toHaveFocus();
expect(menuItems[0]).toHaveTextContent("Manage credentials");
expect(menuItems[1]).toHaveTextContent("API documentation");
expect(menuItems[2]).toHaveTextContent("Delete service");
expect(menuItems[1]).toHaveAttribute(
"href",
"https://cloud.ibm.com/docs/api-gateway/",
);
expect(menuItems[2].parentElement).toHaveClass(
"bx--overflow-menu-options__option--danger",
);
const spy = vi.spyOn(console, "log");
await user.click(menuItems[0]);
expect(spy).toHaveBeenCalledWith("click", "Manage credentials");
expect(menuButton).toHaveAttribute("aria-expanded", "false");
expect(spy).toHaveBeenCalledWith("close", {
index: 0,
text: "Manage credentials",
});
});
it("handles keyboard navigation", async () => {
render(OverflowMenu);
const spy = vi.spyOn(console, "log");
const menuButton = screen.getByRole("button");
await user.click(menuButton);
expect(menuButton).toHaveAttribute("aria-expanded", "true");
let menuItems = screen.getAllByRole("menuitem");
expect(menuItems[0]).toHaveFocus();
await user.keyboard("{ArrowDown}");
expect(menuItems[1]).toHaveFocus();
await user.keyboard("{Enter}");
expect(spy).toHaveBeenCalledWith("click", "API documentation");
await user.click(menuButton);
menuItems = screen.getAllByRole("menuitem");
expect(menuItems[0]).toHaveFocus();
await user.keyboard("{ArrowUp}");
expect(menuItems[2]).toHaveFocus();
await user.keyboard("{Escape}");
expect(menuButton).toHaveAttribute("aria-expanded", "false");
expect(spy).toHaveBeenCalledWith("close", null);
});
it("closes when clicking outside", async () => {
render(OverflowMenu);
const menuButton = screen.getByRole("button");
await user.click(menuButton);
expect(menuButton).toHaveAttribute("aria-expanded", "true");
await user.click(document.body);
expect(menuButton).toHaveAttribute("aria-expanded", "false");
});
it("uses CSS custom properties for performance optimization", async () => {
const { container } = render(OverflowMenu);
const styleTags = document.querySelectorAll("style");
const initialStyleCount = styleTags.length;
expect(styleTags.length).toBe(initialStyleCount);
await user.click(screen.getByRole("button"));
expect(container.querySelector(".bx--overflow-menu-options")).toHaveStyle(
"--overflow-menu-options-after-width: 2rem",
);
expect(styleTags.length).toBe(initialStyleCount);
});
it("stress test: multiple instances don't create individual style tags", async () => {
const { container: container1 } = render(OverflowMenu);
const { container: container2 } = render(OverflowMenu);
const { container: container3 } = render(OverflowMenu);
const styleTagsBefore = document.querySelectorAll("style").length;
const menuButtons1 = container1.querySelectorAll("button");
const menuButtons2 = container2.querySelectorAll("button");
const menuButtons3 = container3.querySelectorAll("button");
await user.click(menuButtons1[0]);
await user.click(menuButtons2[0]);
await user.click(menuButtons3[0]);
const styleTagsAfter = document.querySelectorAll("style").length;
// Verify no additional style tags created (old approach would create 3+)
expect(styleTagsAfter).toBe(styleTagsBefore);
// Verify all menus have CSS custom property set.
const allMenus = [
...container1.querySelectorAll(".bx--overflow-menu-options"),
...container2.querySelectorAll(".bx--overflow-menu-options"),
...container3.querySelectorAll(".bx--overflow-menu-options"),
];
expect(allMenus.length).toBeGreaterThan(0);
allMenus.forEach((menu) => {
expect(menu).toHaveStyle("--overflow-menu-options-after-width: 2rem");
});
});
});