@octopusdeploy/design-system-components
Version:
The design systems component library.
152 lines (151 loc) • 7.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const testing_library_1 = require("@octopusdeploy/testing-library");
const react_1 = require("@testing-library/react");
const vitest_1 = require("vitest");
const MenuList_1 = require("../../../MenuList/MenuList");
const TestDesignSystemProvider_1 = require("../../../TestDesignSystemProvider");
const SimpleMenuItems_1 = require("../../SimpleMenuItems");
(0, vitest_1.describe)("NestedMenu", () => {
(0, vitest_1.test)("entire menu is closed when any nested item is clicked", async () => {
const buttonMenuItem = createButton("my button");
const nestedMenuItem = createNestedMenu("nested menu", [buttonMenuItem]);
const menu = renderMenu([nestedMenuItem]);
const nestedMenu = await menu.clickNestedMenu(nestedMenuItem);
await nestedMenu.clickButton(buttonMenuItem);
nestedMenu.assertButtonWasClicked(buttonMenuItem);
menu.assertMenuWasClosed();
});
(0, vitest_1.test)("first item is focused when menu is expanded", async () => {
const firstButtonMenuItem = createButton("first button");
const secondButtonMenuItem = createButton("second button");
const nestedMenuItem = createNestedMenu("nested menu", [firstButtonMenuItem, secondButtonMenuItem]);
const menu = renderMenu([nestedMenuItem]);
const nestedMenu = await menu.clickNestedMenu(nestedMenuItem);
await nestedMenu.assertItemIsFocused(firstButtonMenuItem);
});
(0, vitest_1.describe)("keyboard interactions", () => {
const firstItem = createButton("first");
const secondItem = createButton("second");
const thirdItem = createButton("third");
const nestedMenuItem = createNestedMenu("nested menu", [firstItem, secondItem, thirdItem]);
async function renderAndOpenNestedMenu() {
const menu = renderMenu([nestedMenuItem]);
const nestedMenu = await menu.clickNestedMenu(nestedMenuItem);
return { menu, nestedMenu };
}
(0, vitest_1.test)("keydown cycles through focused items", async () => {
const { nestedMenu } = await renderAndOpenNestedMenu();
await nestedMenu.pressDownKey();
await nestedMenu.assertItemIsFocused(secondItem);
});
(0, vitest_1.test)("when focused at the bottom of the list, keydown causes focus to wrap around to the top", async () => {
const { nestedMenu } = await renderAndOpenNestedMenu();
await nestedMenu.pressDownKey(); // second item is focused
await nestedMenu.pressDownKey(); // third item is focused
await nestedMenu.pressDownKey(); // first item should be focused again
await nestedMenu.assertItemIsFocused(firstItem);
});
(0, vitest_1.test)("when focused at the top of the list, keyup causes focus to wrap around to the bottom", async () => {
const { nestedMenu } = await renderAndOpenNestedMenu();
await nestedMenu.pressUpKey();
await nestedMenu.assertItemIsFocused(thirdItem);
});
(0, vitest_1.test)("keyup cycles up through the focused items", async () => {
const { nestedMenu } = await renderAndOpenNestedMenu();
await nestedMenu.pressDownKey(); // second item is focused
await nestedMenu.pressUpKey(); // first item is focused again
await nestedMenu.assertItemIsFocused(firstItem);
});
(0, vitest_1.test)("home key focuses the first item", async () => {
const { nestedMenu } = await renderAndOpenNestedMenu();
await nestedMenu.pressDownKey(); // focus something else
await nestedMenu.pressHomeKey();
await nestedMenu.assertItemIsFocused(firstItem);
});
(0, vitest_1.test)("end key focuses the last item", async () => {
const { nestedMenu } = await renderAndOpenNestedMenu();
await nestedMenu.pressEndKey();
await nestedMenu.assertItemIsFocused(thirdItem);
});
(0, vitest_1.test)("typing an items name will focus that item", async () => {
const { nestedMenu } = await renderAndOpenNestedMenu();
await nestedMenu.type(thirdItem.label.substr(0, 2));
await nestedMenu.assertItemIsFocused(thirdItem);
});
(0, vitest_1.test)("Escape closes the entire menu", async () => {
const { nestedMenu, menu } = await renderAndOpenNestedMenu();
nestedMenu.assertMenuIsVisible();
await nestedMenu.pressEscape();
await nestedMenu.assertMenuIsNotVisible();
menu.assertMenuWasClosed();
});
});
});
function createButton(label) {
return {
type: "button",
label,
onClick: vitest_1.vi.fn(),
};
}
function createNestedMenu(label, children) {
return {
type: "nested-menu",
children,
label,
};
}
function renderMenu(menuItems) {
// We need to use a MenuList here to ensure this component works with the keyboard interactions that are provided by MenuList
const onClose = vitest_1.vi.fn();
const rootMenuAccessibleName = "root menu";
(0, react_1.render)((0, jsx_runtime_1.jsx)(TestDesignSystemProvider_1.TestDesignSystemProvider, { children: (0, jsx_runtime_1.jsx)(MenuList_1.MenuList, { accessibleName: rootMenuAccessibleName, children: (0, jsx_runtime_1.jsx)(SimpleMenuItems_1.SimpleMenuItems, { items: menuItems, onClose: onClose }) }) }));
return new RootMenuInteractions(onClose, rootMenuAccessibleName);
}
class MenuInteractions {
menuAccessibleName;
constructor(menuAccessibleName) {
this.menuAccessibleName = menuAccessibleName;
}
clickNestedMenu = async (nestedMenu) => {
await this.getMenu().getMenuItem(nestedMenu.label).click();
return new MenuInteractions(nestedMenu.label);
};
clickButton = async (button) => await this.getMenu().getMenuItem(button.label).click();
getMenu = () => testing_library_1.domQueries.getMenu(this.menuAccessibleName);
queryMenu = () => testing_library_1.domQueries.queryMenu(this.menuAccessibleName);
assertButtonWasClicked = (button) => (0, vitest_1.expect)(button.onClick).toHaveBeenCalled();
assertItemIsFocused = async (button) => {
await testing_library_1.domQueries.getActiveElement().click();
this.assertButtonWasClicked(button);
};
type = async (textToType) => {
await testing_library_1.domQueries.getActiveElement().type(textToType, { skipClick: true });
};
pressUpKey = async () => await pressSpecialKey("ArrowUp");
pressDownKey = async () => await pressSpecialKey("ArrowDown");
pressHomeKey = async () => await pressSpecialKey("Home");
pressEndKey = async () => await pressSpecialKey("End");
pressEscape = async () => await pressSpecialKey("Escape");
assertMenuIsVisible = () => this.getMenu().assertIsInTheDocument();
assertMenuIsNotVisible = async () => {
const menu = this.queryMenu();
if (menu.innerElement) {
await (0, react_1.waitForElementToBeRemoved)(menu.innerElement);
}
menu.assertIsNotInTheDocument();
};
}
class RootMenuInteractions extends MenuInteractions {
onClose;
constructor(onClose, menuAccessibleName) {
super(menuAccessibleName);
this.onClose = onClose;
}
assertMenuWasClosed = () => (0, vitest_1.expect)(this.onClose).toHaveBeenCalled();
}
async function pressSpecialKey(key) {
await testing_library_1.domQueries.getActiveElement().type(`{${key}}`, { skipClick: true });
}