diff --git a/src/components/menu-item/menu-item.e2e.ts b/src/components/menu-item/menu-item.e2e.ts index 522199b173b..753d087ba65 100644 --- a/src/components/menu-item/menu-item.e2e.ts +++ b/src/components/menu-item/menu-item.e2e.ts @@ -46,65 +46,4 @@ describe("calcite-menu-item", () => { }); it("is focusable", () => focusable("calcite-menu-item")); - - describe("mouse support", () => { - it("should open the submenu on click", async () => { - const page = await newE2EPage(); - await page.setContent(html` - - - - - - - - `); - - const menuItem = await page.find("calcite-menu-item[id='ArcGISOnline']"); - const menuItemMenu = await page.find("calcite-menu-item[id='ArcGISOnline'] >>> calcite-menu"); - - expect(await menuItemMenu.isVisible()).toBe(false); - - await menuItem.click(); - await page.waitForChanges(); - expect(await menuItemMenu.isVisible()).toBe(true); - expect(await page.evaluate(() => document.activeElement.id)).toBe("ArcGISOnline"); - - const subMenuItem = await page.find("calcite-menu-item[text='ArcGISJS']"); - const subMenuItemMenu = await page.find("calcite-menu-item[text='ArcGISJS'] >>> calcite-menu"); - expect(await subMenuItemMenu.isVisible()).toBe(false); - await subMenuItem.click(); - await page.waitForChanges(); - expect(await subMenuItemMenu.isVisible()).toBe(true); - expect(await page.evaluate(() => document.activeElement.id)).toBe("ArcGISJS"); - }); - - it("should close any opened submenu when clicked outside", async () => { - const page = await newE2EPage(); - await page.setContent(html` - - - - - `); - - const menuItem = await page.find("calcite-menu-item[id='ArcGISOnline']"); - const menuItemMenu = await page.find("calcite-menu-item[id='ArcGISOnline'] >>> calcite-menu"); - - expect(await menuItemMenu.isVisible()).toBe(false); - - await menuItem.click(); - await page.waitForChanges(); - expect(await menuItemMenu.isVisible()).toBe(true); - expect(await page.evaluate(() => document.activeElement.id)).toBe("ArcGISOnline"); - - const menuElement = await page.$("calcite-menu"); - const { x, y, width, height } = await menuElement.boundingBox(); - - await page.mouse.click(x + width + 50, y + height + 50); - await page.waitForChanges(); - expect(await menuItemMenu.isVisible()).toBe(false); - expect(await page.evaluate(() => document.activeElement.id)).not.toBe("ArcGISOnline"); - }); - }); }); diff --git a/src/components/menu/menu.e2e.ts b/src/components/menu/menu.e2e.ts index 11a480756cb..77ddd101f21 100755 --- a/src/components/menu/menu.e2e.ts +++ b/src/components/menu/menu.e2e.ts @@ -1,3 +1,5 @@ +import { newE2EPage } from "@stencil/core/testing"; +import { html } from "../../../support/formatting"; import { accessible, hidden, renders } from "../../tests/commonTests"; describe("calcite-menu", () => { @@ -6,4 +8,217 @@ describe("calcite-menu", () => { it("honors hidden attribute", async () => hidden("calcite-menu")); it("is accessible", () => accessible("calcite-menu")); + + describe("mouse support", () => { + it("should open the submenu on click", async () => { + const page = await newE2EPage(); + await page.setContent(html` + + + + + + + + `); + + const menuItem = await page.find("calcite-menu-item[id='ArcGISOnline']"); + const menuItemMenu = await page.find("calcite-menu-item[id='ArcGISOnline'] >>> calcite-menu"); + + expect(await menuItemMenu.isVisible()).toBe(false); + + await menuItem.click(); + await page.waitForChanges(); + expect(await menuItemMenu.isVisible()).toBe(true); + expect(await page.evaluate(() => document.activeElement.id)).toBe("ArcGISOnline"); + + const subMenuItem = await page.find("calcite-menu-item[text='ArcGISJS']"); + const subMenuItemMenu = await page.find("calcite-menu-item[text='ArcGISJS'] >>> calcite-menu"); + expect(await subMenuItemMenu.isVisible()).toBe(false); + await subMenuItem.click(); + await page.waitForChanges(); + expect(await subMenuItemMenu.isVisible()).toBe(true); + expect(await page.evaluate(() => document.activeElement.id)).toBe("ArcGISJS"); + }); + + it("should close any opened submenu when clicked outside", async () => { + const page = await newE2EPage(); + await page.setContent(html` + + + + + `); + + const menuItem = await page.find("calcite-menu-item[id='ArcGISOnline']"); + const menuItemMenu = await page.find("calcite-menu-item[id='ArcGISOnline'] >>> calcite-menu"); + + expect(await menuItemMenu.isVisible()).toBe(false); + + await menuItem.click(); + await page.waitForChanges(); + expect(await menuItemMenu.isVisible()).toBe(true); + expect(await page.evaluate(() => document.activeElement.id)).toBe("ArcGISOnline"); + + const menuElement = await page.$("calcite-menu"); + const { x, y, width, height } = await menuElement.boundingBox(); + + await page.mouse.click(x + width + 50, y + height + 50); + await page.waitForChanges(); + expect(await menuItemMenu.isVisible()).toBe(false); + expect(await page.evaluate(() => document.activeElement.id)).not.toBe("ArcGISOnline"); + }); + }); + + describe("keyboard support", () => { + it("should open and close horizontal calcite-menu", async () => { + const page = await newE2EPage(); + await page.setContent(html` + + + + + + + + + + `); + + const menuItemMenu = await page.find("calcite-menu-item[id='Nature'] >>> calcite-menu"); + const subMenuItemMenu = await page.find("calcite-menu-item[id='Mountains'] >>> calcite-menu"); + expect(await menuItemMenu.isVisible()).toBe(false); + + await page.keyboard.press("Tab"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Nature"); + + await page.keyboard.press("Enter"); + expect(await menuItemMenu.isVisible()).toBe(false); + + await page.keyboard.press("Tab"); + await page.keyboard.press("Enter"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Nature"); + await page.waitForChanges(); + expect(await menuItemMenu.isVisible()).toBe(true); + + await page.keyboard.press("ArrowDown"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Mountains"); + + await page.keyboard.press("ArrowDown"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Rivers"); + + await page.keyboard.press("ArrowDown"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Rivers"); + + await page.keyboard.press("ArrowUp"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Mountains"); + + expect(await subMenuItemMenu.isVisible()).toBe(false); + await page.keyboard.press("Enter"); + expect(await subMenuItemMenu.isVisible()).toBe(true); + + await page.keyboard.press("ArrowRight"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Rocky Mountains"); + + await page.keyboard.press("ArrowDown"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Smoky Mountains"); + + await page.keyboard.press("ArrowUp"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Rocky Mountains"); + + await page.keyboard.press("ArrowLeft"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Mountains"); + expect(await subMenuItemMenu.isVisible()).toBe(false); + expect(await menuItemMenu.isVisible()).toBe(true); + + await page.keyboard.press("ArrowLeft"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Nature"); + expect(await menuItemMenu.isVisible()).toBe(false); + + await page.keyboard.press("ArrowRight"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Planets"); + + await page.keyboard.press("ArrowLeft"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Nature"); + }); + + it("should open and close vertical calcite-menu", async () => { + const page = await newE2EPage(); + await page.setContent(html` + + + + + + + + + + `); + + const menuItemMenu = await page.find("calcite-menu-item[id='Nature'] >>> calcite-menu"); + const subMenuItemMenu = await page.find("calcite-menu-item[id='Mountains'] >>> calcite-menu"); + expect(await menuItemMenu.isVisible()).toBe(false); + + await page.keyboard.press("Tab"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Nature"); + + await page.keyboard.press("Enter"); + expect(await menuItemMenu.isVisible()).toBe(false); + + await page.keyboard.press("Tab"); + await page.keyboard.press("Enter"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Nature"); + await page.waitForChanges(); + expect(await menuItemMenu.isVisible()).toBe(true); + + await page.keyboard.press("ArrowRight"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Mountains"); + + await page.keyboard.press("ArrowDown"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Rivers"); + + await page.keyboard.press("ArrowDown"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Rivers"); + + await page.keyboard.press("ArrowUp"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Mountains"); + + expect(await subMenuItemMenu.isVisible()).toBe(false); + await page.keyboard.press("Enter"); + expect(await subMenuItemMenu.isVisible()).toBe(true); + + await page.keyboard.press("ArrowRight"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Rocky Mountains"); + + await page.keyboard.press("ArrowDown"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Smoky Mountains"); + + await page.keyboard.press("ArrowUp"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Rocky Mountains"); + + await page.keyboard.press("ArrowLeft"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Mountains"); + expect(await subMenuItemMenu.isVisible()).toBe(false); + expect(await menuItemMenu.isVisible()).toBe(true); + + await page.keyboard.press("ArrowLeft"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Nature"); + expect(await menuItemMenu.isVisible()).toBe(false); + + await page.keyboard.press("ArrowDown"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Planets"); + + await page.keyboard.press("ArrowUp"); + expect(await page.evaluate(() => document.activeElement.id)).toBe("Nature"); + }); + }); }); diff --git a/src/components/menu/menu.stories.ts b/src/components/menu/menu.stories.ts index 317133daf05..781176fb5b9 100644 --- a/src/components/menu/menu.stories.ts +++ b/src/components/menu/menu.stories.ts @@ -37,3 +37,33 @@ export const withNesting = (): string => html` `; + +export const WithSubMenuOpen_TestOnly = (): string => html` + + + + + `; + +export const WithSubMenuOpenInVerticalLayout_TestOnly = (): string => html` + + + + + `; diff --git a/src/components/menu/menu.tsx b/src/components/menu/menu.tsx index 6f6da55ff72..a9b8c67fbab 100644 --- a/src/components/menu/menu.tsx +++ b/src/components/menu/menu.tsx @@ -115,6 +115,7 @@ export class CalciteMenu { const parentEl = el.parentElement as HTMLCalciteMenuItemElement; if (parentEl) { focusElement(parentEl); + parentEl.open = false; } };