From bf40a055e5ca2756610ae9c5071929c3a41c3e7f Mon Sep 17 00:00:00 2001 From: JC Franco Date: Fri, 1 Dec 2023 13:49:57 -0800 Subject: [PATCH] test(dropdown): fix dropdown E2E suite grouping --- .../src/components/dropdown/dropdown.e2e.ts | 2019 ++++++++--------- 1 file changed, 1008 insertions(+), 1011 deletions(-) diff --git a/packages/calcite-components/src/components/dropdown/dropdown.e2e.ts b/packages/calcite-components/src/components/dropdown/dropdown.e2e.ts index 70df138aa16..c66da292d5b 100644 --- a/packages/calcite-components/src/components/dropdown/dropdown.e2e.ts +++ b/packages/calcite-components/src/components/dropdown/dropdown.e2e.ts @@ -37,1200 +37,1197 @@ describe("calcite-dropdown", () => { defaultValue: "bottom-start", }, ]); + }); - describe("reflects", () => { - reflects("calcite-dropdown", [ - { - propertyName: "scale", - value: "m", - }, - { - propertyName: "placement", - value: "bottom-start", - }, - ]); - }); - - describe("focusable", () => { - focusable(simpleDropdownHTML, { - focusTargetSelector: '[slot="trigger"]', - }); - }); + describe("reflects", () => { + reflects("calcite-dropdown", [ + { + propertyName: "scale", + value: "m", + }, + { + propertyName: "placement", + value: "bottom-start", + }, + ]); + }); - describe("renders", () => { - renders(simpleDropdownHTML, { display: "inline-flex" }); + describe("focusable", () => { + focusable(simpleDropdownHTML, { + focusTargetSelector: '[slot="trigger"]', }); + }); - describe("honors hidden attribute", () => { - hidden("calcite-dropdown"); - }); + describe("renders", () => { + renders(simpleDropdownHTML, { display: "inline-flex" }); + }); - describe.skip("disabled", () => { - disabled(simpleDropdownHTML, { - focusTarget: { - tab: "calcite-button", - click: "calcite-dropdown-item", - }, - }); - }); + describe("honors hidden attribute", () => { + hidden("calcite-dropdown"); + }); - describe("openClose", () => { - openClose(simpleDropdownHTML); + describe.skip("disabled", () => { + disabled(simpleDropdownHTML, { + focusTarget: { + tab: "calcite-button", + click: "calcite-dropdown-item", + }, }); + }); - interface SelectedItemsAssertionOptions { - /** - * IDs from items to assert selection - */ - expectedItemIds: string[]; - } + describe("openClose", () => { + openClose(simpleDropdownHTML); + }); + interface SelectedItemsAssertionOptions { /** - * Test helper for selected calcite-dropdown items. Expects items to have IDs to test against. - * - * Note: assertSelectedItems.setUpEvents must be called before using this method - * - * @param page - * @param root0 - * @param root0.expectedItemIds + * IDs from items to assert selection */ - async function assertSelectedItems( - page: E2EPage, - { expectedItemIds }: SelectedItemsAssertionOptions - ): Promise { - await page.waitForTimeout(100); - const selectedItemIds = await page.evaluate(() => { - const dropdown = document.querySelector("calcite-dropdown"); - return dropdown.selectedItems.map((item) => item.id); - }); + expectedItemIds: string[]; + } + + /** + * Test helper for selected calcite-dropdown items. Expects items to have IDs to test against. + * + * Note: assertSelectedItems.setUpEvents must be called before using this method + * + * @param page + * @param root0 + * @param root0.expectedItemIds + */ + async function assertSelectedItems(page: E2EPage, { expectedItemIds }: SelectedItemsAssertionOptions): Promise { + await page.waitForTimeout(100); + const selectedItemIds = await page.evaluate(() => { + const dropdown = document.querySelector("calcite-dropdown"); + return dropdown.selectedItems.map((item) => item.id); + }); - expect(selectedItemIds).toHaveLength(expectedItemIds.length); + expect(selectedItemIds).toHaveLength(expectedItemIds.length); - expectedItemIds.forEach((itemId, index) => expect(selectedItemIds[index]).toEqual(itemId)); - } + expectedItemIds.forEach((itemId, index) => expect(selectedItemIds[index]).toEqual(itemId)); + } - type SelectionEventTestWindow = GlobalTestProps<{ eventDetail: Selection }>; + type SelectionEventTestWindow = GlobalTestProps<{ eventDetail: Selection }>; - /** - * Helper to wire up the page to assert on the event detail - * - * @param page - */ - assertSelectedItems.setUpEvents = async (page: E2EPage) => { - await page.evaluate(() => { - document.addEventListener("calciteDropdownSelect", ({ detail }: CustomEvent) => { - (window as SelectionEventTestWindow).eventDetail = detail; - }); + /** + * Helper to wire up the page to assert on the event detail + * + * @param page + */ + assertSelectedItems.setUpEvents = async (page: E2EPage) => { + await page.evaluate(() => { + document.addEventListener("calciteDropdownSelect", ({ detail }: CustomEvent) => { + (window as SelectionEventTestWindow).eventDetail = detail; }); - }; - - const dropdownSelectionModeContent = html` - - Open dropdown - - Dropdown Item Content - Dropdown Item Content - Dropdown Item Content - - - Dropdown Item Content - Dropdown Item Content - - - Dropdown Item Content - Dropdown Item Content - - - `; - - it("renders requested props when valid props are provided", async () => { - const page = await newE2EPage(); - await page.setContent(html` - Open dropdown - - Dropdown Item Content - Dropdown Item Content - Dropdown Item Content - - `); - - const element = await page.find("calcite-dropdown"); - const group1 = await element.find("calcite-dropdown-group[id='group-1']"); - - expect(element).toEqualAttribute("width", "l"); - expect(element).toEqualAttribute("placement", "bottom-end"); - expect(group1).toEqualAttribute("selection-mode", "multiple"); }); + }; - it("inheritable non-default props `selectionMode` and `scale` set on parent get passed into items", async () => { - const page = await newE2EPage(); - await page.setContent(html` - - Open dropdown - - Content - Content - Content - - - `); - const dropdownItems = await page.findAll("calcite-dropdown-items"); + const dropdownSelectionModeContent = html` + + Open dropdown + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + + Dropdown Item Content + Dropdown Item Content + + + Dropdown Item Content + Dropdown Item Content + + + `; - dropdownItems.forEach(async (item) => { - expect(await item.getProperty("selectionMode")).toBe("single-persist"); - expect(await item.getProperty("scale")).toBe("s"); - }); - }); + it("renders requested props when valid props are provided", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + `); - it("renders icons if requested and does not render icons if not requested", async () => { - const page = await newE2EPage(); - await page.setContent(html` - Open dropdown - - Dropdown Item Content - Dropdown Item Content - - Dropdown Item Content - - Dropdown Item Content - - `); + const element = await page.find("calcite-dropdown"); + const group1 = await element.find("calcite-dropdown-group[id='group-1']"); - const item1IconStart = await page.find("calcite-dropdown-item[id='item-1'] >>> .dropdown-item-icon-start"); - const item1IconEnd = await page.find("calcite-dropdown-item[id='item-1'] >>> .dropdown-item-icon-end"); - const item2IconStart = await page.find("calcite-dropdown-item[id='item-2'] >>> .dropdown-item-icon-start"); - const item2IconEnd = await page.find("calcite-dropdown-item[id='item-2'] >>> .dropdown-item-icon-end"); - const item3IconStart = await page.find("calcite-dropdown-item[id='item-3'] >>> .dropdown-item-icon-start"); - const item3IconEnd = await page.find("calcite-dropdown-item[id='item-3'] >>> .dropdown-item-icon-end"); - const item4IconStart = await page.find("calcite-dropdown-item[id='item-4'] >>> .dropdown-item-icon-start"); - const item4IconEnd = await page.find("calcite-dropdown-item[id='item-4'] >>> .dropdown-item-icon-end"); - expect(item1IconStart).not.toBeNull(); - expect(item1IconEnd).toBeNull(); - expect(item2IconStart).toBeNull(); - expect(item2IconEnd).not.toBeNull(); - expect(item3IconStart).not.toBeNull(); - expect(item3IconEnd).not.toBeNull(); - expect(item4IconStart).toBeNull(); - expect(item4IconEnd).toBeNull(); - }); + expect(element).toEqualAttribute("width", "l"); + expect(element).toEqualAttribute("placement", "bottom-end"); + expect(group1).toEqualAttribute("selection-mode", "multiple"); + }); - it("renders group title if specified and not if absent", async () => { - const page = await newE2EPage(); - await page.setContent(html` + it("inheritable non-default props `selectionMode` and `scale` set on parent get passed into items", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown - - Dropdown Item Content - Dropdown Item Content - - - Dropdown Item Content - Dropdown Item Content + + Content + Content + Content - `); + + `); + const dropdownItems = await page.findAll("calcite-dropdown-items"); - const group1Title = await page.find("calcite-dropdown-group[id='group-1'] >>> .dropdown-title"); - const group2Title = await page.find("calcite-dropdown-group[id='group-2'] >>> .dropdown-title"); - expect(group1Title).not.toBeNull(); - expect(group2Title).toBeNull(); + dropdownItems.forEach(async (item) => { + expect(await item.getProperty("selectionMode")).toBe("single-persist"); + expect(await item.getProperty("scale")).toBe("s"); }); + }); - it("renders selected item based on attribute in dom", async () => { - const page = await newE2EPage(); - await page.setContent(html` - Open dropdown - - Dropdown Item Content - Dropdown Item Content - Dropdown Item Content - - `); + it("renders icons if requested and does not render icons if not requested", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown + + Dropdown Item Content + Dropdown Item Content + + Dropdown Item Content + + Dropdown Item Content + + `); + + const item1IconStart = await page.find("calcite-dropdown-item[id='item-1'] >>> .dropdown-item-icon-start"); + const item1IconEnd = await page.find("calcite-dropdown-item[id='item-1'] >>> .dropdown-item-icon-end"); + const item2IconStart = await page.find("calcite-dropdown-item[id='item-2'] >>> .dropdown-item-icon-start"); + const item2IconEnd = await page.find("calcite-dropdown-item[id='item-2'] >>> .dropdown-item-icon-end"); + const item3IconStart = await page.find("calcite-dropdown-item[id='item-3'] >>> .dropdown-item-icon-start"); + const item3IconEnd = await page.find("calcite-dropdown-item[id='item-3'] >>> .dropdown-item-icon-end"); + const item4IconStart = await page.find("calcite-dropdown-item[id='item-4'] >>> .dropdown-item-icon-start"); + const item4IconEnd = await page.find("calcite-dropdown-item[id='item-4'] >>> .dropdown-item-icon-end"); + expect(item1IconStart).not.toBeNull(); + expect(item1IconEnd).toBeNull(); + expect(item2IconStart).toBeNull(); + expect(item2IconEnd).not.toBeNull(); + expect(item3IconStart).not.toBeNull(); + expect(item3IconEnd).not.toBeNull(); + expect(item4IconStart).toBeNull(); + expect(item4IconEnd).toBeNull(); + }); - const element = await page.find("calcite-dropdown"); - const item1 = await element.find("calcite-dropdown-item[id='item-1']"); - const item2 = await element.find("calcite-dropdown-item[id='item-2']"); - const item3 = await element.find("calcite-dropdown-item[id='item-3']"); + it("renders group title if specified and not if absent", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown + + Dropdown Item Content + Dropdown Item Content + + + Dropdown Item Content + Dropdown Item Content + + `); - expect(item1).not.toHaveAttribute("selected"); - expect(item2).toHaveAttribute("selected"); - expect(item3).not.toHaveAttribute("selected"); - }); + const group1Title = await page.find("calcite-dropdown-group[id='group-1'] >>> .dropdown-title"); + const group2Title = await page.find("calcite-dropdown-group[id='group-2'] >>> .dropdown-title"); + expect(group1Title).not.toBeNull(); + expect(group2Title).toBeNull(); + }); - it("renders multiple selected items when group is in multiple selection mode", async () => { - const page = await newE2EPage(); - await page.setContent(html` - - Open dropdown - - Dropdown Item Content - Dropdown Item Content - Dropdown Item Content - - - `); + it("renders selected item based on attribute in dom", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + `); - const element = await page.find("calcite-dropdown"); - const trigger = await element.find("#trigger"); - const group1 = await element.find("calcite-dropdown-group[id='group-1']"); - const item1 = await element.find("calcite-dropdown-item[id='item-1']"); - const item2 = await element.find("calcite-dropdown-item[id='item-2']"); - const item3 = await element.find("calcite-dropdown-item[id='item-3']"); - const itemChangeSpy = await element.spyOnEvent("calciteDropdownSelect"); - await assertSelectedItems.setUpEvents(page); - expect(group1).toEqualAttribute("selection-mode", "multiple"); - await trigger.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { expectedItemIds: ["item-2"] }); - await item1.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { - expectedItemIds: ["item-1", "item-2"], - }); - await trigger.click(); - await page.waitForChanges(); - await item2.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { - expectedItemIds: ["item-1"], - }); - await trigger.click(); - await page.waitForChanges(); - await item3.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { - expectedItemIds: ["item-1", "item-3"], - }); + const element = await page.find("calcite-dropdown"); + const item1 = await element.find("calcite-dropdown-item[id='item-1']"); + const item2 = await element.find("calcite-dropdown-item[id='item-2']"); + const item3 = await element.find("calcite-dropdown-item[id='item-3']"); - expect(item1).toHaveAttribute("selected"); - expect(item2).not.toHaveAttribute("selected"); - expect(item3).toHaveAttribute("selected"); - expect(itemChangeSpy).toHaveReceivedEventTimes(3); - }); + expect(item1).not.toHaveAttribute("selected"); + expect(item2).toHaveAttribute("selected"); + expect(item3).not.toHaveAttribute("selected"); + }); - it("renders just one selected item when group is in single selection mode", async () => { - const page = await newE2EPage(); - await page.setContent(html` + it("renders multiple selected items when group is in multiple selection mode", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown - + Dropdown Item Content Dropdown Item Content Dropdown Item Content - `); + + `); + + const element = await page.find("calcite-dropdown"); + const trigger = await element.find("#trigger"); + const group1 = await element.find("calcite-dropdown-group[id='group-1']"); + const item1 = await element.find("calcite-dropdown-item[id='item-1']"); + const item2 = await element.find("calcite-dropdown-item[id='item-2']"); + const item3 = await element.find("calcite-dropdown-item[id='item-3']"); + const itemChangeSpy = await element.spyOnEvent("calciteDropdownSelect"); + await assertSelectedItems.setUpEvents(page); + expect(group1).toEqualAttribute("selection-mode", "multiple"); + await trigger.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { expectedItemIds: ["item-2"] }); + await item1.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { + expectedItemIds: ["item-1", "item-2"], + }); + await trigger.click(); + await page.waitForChanges(); + await item2.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { + expectedItemIds: ["item-1"], + }); + await trigger.click(); + await page.waitForChanges(); + await item3.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { + expectedItemIds: ["item-1", "item-3"], + }); - const element = await page.find("calcite-dropdown"); - const trigger = await element.find("#trigger"); - const group1 = await element.find("calcite-dropdown-group[id='group-1']"); - const item1 = await element.find("calcite-dropdown-item[id='item-1']"); - const item2 = await element.find("calcite-dropdown-item[id='item-2']"); - const item3 = await element.find("calcite-dropdown-item[id='item-3']"); - const itemChangeSpy = await element.spyOnEvent("calciteDropdownSelect"); - await assertSelectedItems.setUpEvents(page); - expect(group1).toEqualAttribute("selection-mode", "single"); - await assertSelectedItems(page, { expectedItemIds: ["item-2"] }); - await trigger.click(); - await page.waitForChanges(); - await item1.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { - expectedItemIds: ["item-1"], - }); - await trigger.click(); - await page.waitForChanges(); - await item3.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { - expectedItemIds: ["item-3"], - }); + expect(item1).toHaveAttribute("selected"); + expect(item2).not.toHaveAttribute("selected"); + expect(item3).toHaveAttribute("selected"); + expect(itemChangeSpy).toHaveReceivedEventTimes(3); + }); - expect(item1).not.toHaveAttribute("selected"); - expect(item2).not.toHaveAttribute("selected"); - expect(item3).toHaveAttribute("selected"); - expect(itemChangeSpy).toHaveReceivedEventTimes(2); + it("renders just one selected item when group is in single selection mode", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + `); + + const element = await page.find("calcite-dropdown"); + const trigger = await element.find("#trigger"); + const group1 = await element.find("calcite-dropdown-group[id='group-1']"); + const item1 = await element.find("calcite-dropdown-item[id='item-1']"); + const item2 = await element.find("calcite-dropdown-item[id='item-2']"); + const item3 = await element.find("calcite-dropdown-item[id='item-3']"); + const itemChangeSpy = await element.spyOnEvent("calciteDropdownSelect"); + await assertSelectedItems.setUpEvents(page); + expect(group1).toEqualAttribute("selection-mode", "single"); + await assertSelectedItems(page, { expectedItemIds: ["item-2"] }); + await trigger.click(); + await page.waitForChanges(); + await item1.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { + expectedItemIds: ["item-1"], + }); + await trigger.click(); + await page.waitForChanges(); + await item3.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { + expectedItemIds: ["item-3"], }); - it("renders no selected item when group is in none selection mode (and removes any selected state set in dom on load)", async () => { - const page = await newE2EPage(); - await page.setContent(html` - Open dropdown - - Dropdown Item Content - Dropdown Item Content - Dropdown Item Content - - `); + expect(item1).not.toHaveAttribute("selected"); + expect(item2).not.toHaveAttribute("selected"); + expect(item3).toHaveAttribute("selected"); + expect(itemChangeSpy).toHaveReceivedEventTimes(2); + }); - const element = await page.find("calcite-dropdown"); - const trigger = await element.find("#trigger"); - const group1 = await element.find("calcite-dropdown-group[id='group-1']"); - const item1 = await element.find("calcite-dropdown-item[id='item-1']"); - const item2 = await element.find("calcite-dropdown-item[id='item-2']"); - const item3 = await element.find("calcite-dropdown-item[id='item-3']"); - const itemChangeSpy = await element.spyOnEvent("calciteDropdownSelect"); - await assertSelectedItems.setUpEvents(page); - expect(group1).toEqualAttribute("selection-mode", "none"); - await trigger.click(); - await item1.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { expectedItemIds: [] }); - await trigger.click(); - await item2.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { expectedItemIds: [] }); - await trigger.click(); - await item3.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { expectedItemIds: [] }); + it("renders no selected item when group is in none selection mode (and removes any selected state set in dom on load)", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + `); + + const element = await page.find("calcite-dropdown"); + const trigger = await element.find("#trigger"); + const group1 = await element.find("calcite-dropdown-group[id='group-1']"); + const item1 = await element.find("calcite-dropdown-item[id='item-1']"); + const item2 = await element.find("calcite-dropdown-item[id='item-2']"); + const item3 = await element.find("calcite-dropdown-item[id='item-3']"); + const itemChangeSpy = await element.spyOnEvent("calciteDropdownSelect"); + await assertSelectedItems.setUpEvents(page); + expect(group1).toEqualAttribute("selection-mode", "none"); + await trigger.click(); + await item1.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { expectedItemIds: [] }); + await trigger.click(); + await item2.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { expectedItemIds: [] }); + await trigger.click(); + await item3.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { expectedItemIds: [] }); + + expect(item1).not.toHaveAttribute("selected"); + expect(item2).not.toHaveAttribute("selected"); + expect(item3).not.toHaveAttribute("selected"); + expect(itemChangeSpy).toHaveReceivedEventTimes(3); + }); - expect(item1).not.toHaveAttribute("selected"); - expect(item2).not.toHaveAttribute("selected"); - expect(item3).not.toHaveAttribute("selected"); - expect(itemChangeSpy).toHaveReceivedEventTimes(3); + it("renders the correct selected state when parent contains groups of assorted selection modes", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + `); + + const element = await page.find("calcite-dropdown"); + const trigger = await element.find("#trigger"); + const group1 = await element.find("calcite-dropdown-group[id='group-1']"); + const group2 = await element.find("calcite-dropdown-group[id='group-2']"); + const group3 = await element.find("calcite-dropdown-group[id='group-3']"); + const item1 = await element.find("calcite-dropdown-item[id='item-1']"); + const item2 = await element.find("calcite-dropdown-item[id='item-2']"); + const item3 = await element.find("calcite-dropdown-item[id='item-3']"); + const item4 = await element.find("calcite-dropdown-item[id='item-4']"); + const item5 = await element.find("calcite-dropdown-item[id='item-5']"); + const item6 = await element.find("calcite-dropdown-item[id='item-6']"); + const item7 = await element.find("calcite-dropdown-item[id='item-7']"); + const item8 = await element.find("calcite-dropdown-item[id='item-8']"); + const item9 = await element.find("calcite-dropdown-item[id='item-9']"); + const itemChangeSpy = await element.spyOnEvent("calciteDropdownSelect"); + await assertSelectedItems.setUpEvents(page); + + expect(group1).toEqualAttribute("selection-mode", "multiple"); + expect(group2).toEqualAttribute("selection-mode", "single"); + expect(group3).toEqualAttribute("selection-mode", "none"); + await assertSelectedItems(page, { expectedItemIds: ["item-2", "item-5"] }); + + await trigger.click(); + await page.waitForChanges(); + await item1.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { + expectedItemIds: ["item-1", "item-2", "item-5"], + }); + await trigger.click(); + await page.waitForChanges(); + await item2.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { + expectedItemIds: ["item-1", "item-5"], + }); + await trigger.click(); + await page.waitForChanges(); + await item3.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { + expectedItemIds: ["item-1", "item-3", "item-5"], + }); + await trigger.click(); + await page.waitForChanges(); + await item4.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { + expectedItemIds: ["item-1", "item-3", "item-4"], + }); + await trigger.click(); + await page.waitForChanges(); + await item6.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { + expectedItemIds: ["item-1", "item-3", "item-6"], + }); + await trigger.click(); + await page.waitForChanges(); + await item7.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { + expectedItemIds: ["item-1", "item-3", "item-6"], + }); + await trigger.click(); + await page.waitForChanges(); + await item9.click(); + await page.waitForChanges(); + await assertSelectedItems(page, { + expectedItemIds: ["item-1", "item-3", "item-6"], }); - it("renders the correct selected state when parent contains groups of assorted selection modes", async () => { - const page = await newE2EPage(); - await page.setContent(html` - Open dropdown - - Dropdown Item Content - Dropdown Item Content - Dropdown Item Content - - - Dropdown Item Content - Dropdown Item Content - Dropdown Item Content - - - Dropdown Item Content - Dropdown Item Content - Dropdown Item Content - - `); - - const element = await page.find("calcite-dropdown"); - const trigger = await element.find("#trigger"); - const group1 = await element.find("calcite-dropdown-group[id='group-1']"); - const group2 = await element.find("calcite-dropdown-group[id='group-2']"); - const group3 = await element.find("calcite-dropdown-group[id='group-3']"); - const item1 = await element.find("calcite-dropdown-item[id='item-1']"); - const item2 = await element.find("calcite-dropdown-item[id='item-2']"); - const item3 = await element.find("calcite-dropdown-item[id='item-3']"); - const item4 = await element.find("calcite-dropdown-item[id='item-4']"); - const item5 = await element.find("calcite-dropdown-item[id='item-5']"); - const item6 = await element.find("calcite-dropdown-item[id='item-6']"); - const item7 = await element.find("calcite-dropdown-item[id='item-7']"); - const item8 = await element.find("calcite-dropdown-item[id='item-8']"); - const item9 = await element.find("calcite-dropdown-item[id='item-9']"); - const itemChangeSpy = await element.spyOnEvent("calciteDropdownSelect"); - await assertSelectedItems.setUpEvents(page); - - expect(group1).toEqualAttribute("selection-mode", "multiple"); - expect(group2).toEqualAttribute("selection-mode", "single"); - expect(group3).toEqualAttribute("selection-mode", "none"); - await assertSelectedItems(page, { expectedItemIds: ["item-2", "item-5"] }); + expect(item1).toHaveAttribute("selected"); + expect(item2).not.toHaveAttribute("selected"); + expect(item3).toHaveAttribute("selected"); + expect(item4).not.toHaveAttribute("selected"); + expect(item5).not.toHaveAttribute("selected"); + expect(item6).toHaveAttribute("selected"); + expect(item7).not.toHaveAttribute("selected"); + expect(item8).not.toHaveAttribute("selected"); + expect(item9).not.toHaveAttribute("selected"); + expect(itemChangeSpy).toHaveReceivedEventTimes(7); + }); - await trigger.click(); - await page.waitForChanges(); - await item1.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { - expectedItemIds: ["item-1", "item-2", "item-5"], - }); - await trigger.click(); - await page.waitForChanges(); - await item2.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { - expectedItemIds: ["item-1", "item-5"], - }); - await trigger.click(); - await page.waitForChanges(); - await item3.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { - expectedItemIds: ["item-1", "item-3", "item-5"], - }); - await trigger.click(); - await page.waitForChanges(); - await item4.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { - expectedItemIds: ["item-1", "item-3", "item-4"], - }); - await trigger.click(); - await page.waitForChanges(); - await item6.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { - expectedItemIds: ["item-1", "item-3", "item-6"], - }); - await trigger.click(); - await page.waitForChanges(); - await item7.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { - expectedItemIds: ["item-1", "item-3", "item-6"], - }); - await trigger.click(); - await page.waitForChanges(); - await item9.click(); - await page.waitForChanges(); - await assertSelectedItems(page, { - expectedItemIds: ["item-1", "item-3", "item-6"], - }); + it("renders a calcite-dropdown-item with child anchor link with passed attributes if href is present", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown + + Dropdown Item Content + + Dropdown Item Content + + Dropdown Item Content + + `); + const elementAsLink = await page.find("calcite-dropdown-item[id='item-2'] >>> a"); + expect(elementAsLink).not.toBeNull(); + expect(elementAsLink).toEqualAttribute("href", "google.com"); + expect(elementAsLink).toEqualAttribute("rel", "noopener noreferrer"); + expect(elementAsLink).toEqualAttribute("target", "_blank"); + }); - expect(item1).toHaveAttribute("selected"); - expect(item2).not.toHaveAttribute("selected"); - expect(item3).toHaveAttribute("selected"); - expect(item4).not.toHaveAttribute("selected"); - expect(item5).not.toHaveAttribute("selected"); - expect(item6).toHaveAttribute("selected"); - expect(item7).not.toHaveAttribute("selected"); - expect(item8).not.toHaveAttribute("selected"); - expect(item9).not.toHaveAttribute("selected"); - expect(itemChangeSpy).toHaveReceivedEventTimes(7); + it("should focus the first item on open when there is no selected item", async () => { + const page = await newE2EPage({ + html: html` + Open Dropdown + + 1 + 2 + 3 + 4 + + `, }); - it("renders a calcite-dropdown-item with child anchor link with passed attributes if href is present", async () => { - const page = await newE2EPage(); - await page.setContent(html` - Open dropdown - - Dropdown Item Content - - Dropdown Item Content - - Dropdown Item Content + const element = await page.find("calcite-dropdown"); + const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); + await element.click(); + await dropdownOpenEvent; + expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-1"); + }); + + it("should focus the first selected item on open", async () => { + const page = await newE2EPage({ + html: html` + Open Dropdown + + 1 + 2 + 3 + 4 - `); - const elementAsLink = await page.find("calcite-dropdown-item[id='item-2'] >>> a"); - expect(elementAsLink).not.toBeNull(); - expect(elementAsLink).toEqualAttribute("href", "google.com"); - expect(elementAsLink).toEqualAttribute("rel", "noopener noreferrer"); - expect(elementAsLink).toEqualAttribute("target", "_blank"); + `, }); - it("should focus the first item on open when there is no selected item", async () => { - const page = await newE2EPage({ - html: html` - Open Dropdown - - 1 - 2 - 3 - 4 - - `, - }); + const element = await page.find("calcite-dropdown"); + const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); + await element.click(); + await dropdownOpenEvent; - const element = await page.find("calcite-dropdown"); - const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); - await element.click(); - await dropdownOpenEvent; - expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-1"); + expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-3"); + }); + + it("should focus the first selected item on open (multi)", async () => { + const page = await newE2EPage({ + html: html` + Open Dropdown + + 1 + 2 + 3 + 4 + + `, }); - it("should focus the first selected item on open", async () => { - const page = await newE2EPage({ - html: html` - Open Dropdown - - 1 - 2 - 3 - 4 - - `, - }); + const element = await page.find("calcite-dropdown"); + const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); + await element.click(); + await dropdownOpenEvent; - const element = await page.find("calcite-dropdown"); - const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); - await element.click(); - await dropdownOpenEvent; + expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-2"); + }); - expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-3"); - }); + describe("scrolling", () => { + it("focused item should be in view when long", async () => { + const page = await newE2EPage(); - it("should focus the first selected item on open (multi)", async () => { - const page = await newE2EPage({ - html: html` - Open Dropdown - - 1 - 2 - 3 - 4 - - `, - }); + await page.setContent(html` + Open Dropdown + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + + `); + await page.waitForChanges(); const element = await page.find("calcite-dropdown"); const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); await element.click(); await dropdownOpenEvent; - expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-2"); - }); + expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-50"); - describe("scrolling", () => { - it("focused item should be in view when long", async () => { - const page = await newE2EPage(); + const item = await page.find("#item-50"); - await page.setContent(html` + expect(await item.isIntersectingViewport()).toBe(true); + }); + + it("control max items displayed", async () => { + const maxItems = 7; + const page = await newE2EPage({ + html: html` Open Dropdown - + 1 2 3 4 5 + + 6 7 8 9 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - 22 - 23 - 24 - 25 - 26 - 27 - 28 - 29 - 30 - 41 - 42 - 43 - 44 - 45 - 46 - 47 - 48 - 49 - 50 - `); - await page.waitForChanges(); - - const element = await page.find("calcite-dropdown"); - const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); - await element.click(); - await dropdownOpenEvent; - - expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-50"); + `, + }); - const item = await page.find("#item-50"); + const element = await page.find("calcite-dropdown"); + const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); + await element.click(); + await dropdownOpenEvent; - expect(await item.isIntersectingViewport()).toBe(true); - }); + const items = await page.findAll("calcite-dropdown-item"); - it("control max items displayed", async () => { - const maxItems = 7; - const page = await newE2EPage({ - html: html` - Open Dropdown - - 1 - 2 - 3 - 4 - 5 - - - 6 - 7 - 8 - 9 - 10 - - `, - }); + for (let i = 0; i < items.length; i++) { + expect(await items[i].isIntersectingViewport()).toBe(i <= maxItems - 1); + } - const element = await page.find("calcite-dropdown"); - const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); - await element.click(); - await dropdownOpenEvent; + const newMaxItems = 4; + element.setProperty("maxItems", newMaxItems); + await page.waitForChanges(); - const items = await page.findAll("calcite-dropdown-item"); + for (let i = 0; i < items.length; i++) { + expect(await items[i].isIntersectingViewport()).toBe(i <= newMaxItems - 1); + } + }); + }); - for (let i = 0; i < items.length; i++) { - expect(await items[i].isIntersectingViewport()).toBe(i <= maxItems - 1); - } + it("closes when a selection is made", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + `); + + const element = await page.find("calcite-dropdown"); + const trigger = await element.find("#trigger"); + const item1 = await element.find("calcite-dropdown-item[id='item-1']"); + const dropdownWrapper = await page.find("calcite-dropdown >>> .calcite-dropdown-wrapper"); + expect(await dropdownWrapper.isVisible()).toBe(false); + await trigger.click(); + await page.waitForChanges(); + expect(await dropdownWrapper.isVisible()).toBe(true); + await item1.click(); + await page.waitForChanges(); + expect(await dropdownWrapper.isVisible()).toBe(false); + }); - const newMaxItems = 4; - element.setProperty("maxItems", newMaxItems); - await page.waitForChanges(); + it("remains open when close-on-select-disabled is requested and selected item is not in a selection-mode:none group", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown + + Dropdown Item Content + Dropdown Item Content + +
Dropdown Item Content
+
+
+
`); + + const element = await page.find("calcite-dropdown"); + const trigger = await element.find("#trigger"); + const item1 = await element.find("#item-1"); + const item3 = await element.find("#item-3"); + const dropdownWrapper = await page.find("calcite-dropdown >>> .calcite-dropdown-wrapper"); + expect(await dropdownWrapper.isVisible()).toBe(false); + await trigger.click(); + await page.waitForChanges(); + expect(await dropdownWrapper.isVisible()).toBe(true); + await item1.click(); + await page.waitForChanges(); + expect(await dropdownWrapper.isVisible()).toBe(true); + await item3.click(); + await page.waitForChanges(); + expect(await dropdownWrapper.isVisible()).toBe(true); + }); - for (let i = 0; i < items.length; i++) { - expect(await items[i].isIntersectingViewport()).toBe(i <= newMaxItems - 1); - } - }); - }); + it("closes when close-on-select-disabled is requested and selected item is in a selection-mode:none group", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown + + +
Dropdown Item Content
+
+ Dropdown Item Content + Dropdown Item Content +
+
`); + + const element = await page.find("calcite-dropdown"); + const trigger = await element.find("#trigger"); + const item1 = await element.find("#item-1"); + const dropdownWrapper = await page.find("calcite-dropdown >>> .calcite-dropdown-wrapper"); + expect(await dropdownWrapper.isVisible()).toBe(false); + await trigger.click(); + await page.waitForChanges(); + expect(await dropdownWrapper.isVisible()).toBe(true); + await item1.click(); + await page.waitForChanges(); + expect(await dropdownWrapper.isVisible()).toBe(false); + }); - it("closes when a selection is made", async () => { + describe("toggles the dropdown with click, enter, or space", () => { + it("toggles when trigger is a button", async () => { const page = await newE2EPage(); - await page.setContent(html` - Open dropdown - - Dropdown Item Content - Dropdown Item Content - Dropdown Item Content - - `); - + await page.setContent(html` + + Open dropdown + + Dropdown Item Content + Dropdown Item Content + + + `); const element = await page.find("calcite-dropdown"); - const trigger = await element.find("#trigger"); - const item1 = await element.find("calcite-dropdown-item[id='item-1']"); - const dropdownWrapper = await page.find("calcite-dropdown >>> .calcite-dropdown-wrapper"); + const trigger = await element.find("calcite-button[slot='trigger']"); + const dropdownWrapper = await page.find(`calcite-dropdown >>> .calcite-dropdown-wrapper`); + const calciteDropdownOpen = await element.spyOnEvent("calciteDropdownOpen"); + const calciteDropdownClose = await element.spyOnEvent("calciteDropdownClose"); + let waitForCalciteDropdownOpen = page.waitForEvent("calciteDropdownOpen"); + const waitForCalciteDropdownClose = page.waitForEvent("calciteDropdownClose"); + expect(await dropdownWrapper.isVisible()).toBe(false); await trigger.click(); await page.waitForChanges(); expect(await dropdownWrapper.isVisible()).toBe(true); - await item1.click(); + await waitForCalciteDropdownOpen; + expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); + expect(calciteDropdownClose).toHaveReceivedEventTimes(0); + + await element.callMethod("setFocus"); + await page.waitForChanges(); + await page.keyboard.press("Space"); await page.waitForChanges(); expect(await dropdownWrapper.isVisible()).toBe(false); - }); + await waitForCalciteDropdownClose; + expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); + expect(calciteDropdownClose).toHaveReceivedEventTimes(1); - it("remains open when close-on-select-disabled is requested and selected item is not in a selection-mode:none group", async () => { - const page = await newE2EPage(); - await page.setContent(html` - Open dropdown - - Dropdown Item Content - Dropdown Item Content - -
Dropdown Item Content
-
-
-
`); + waitForCalciteDropdownOpen = page.waitForEvent("calciteDropdownOpen"); - const element = await page.find("calcite-dropdown"); - const trigger = await element.find("#trigger"); - const item1 = await element.find("#item-1"); - const item3 = await element.find("#item-3"); - const dropdownWrapper = await page.find("calcite-dropdown >>> .calcite-dropdown-wrapper"); - expect(await dropdownWrapper.isVisible()).toBe(false); - await trigger.click(); - await page.waitForChanges(); - expect(await dropdownWrapper.isVisible()).toBe(true); - await item1.click(); - await page.waitForChanges(); - expect(await dropdownWrapper.isVisible()).toBe(true); - await item3.click(); + await page.keyboard.press("Enter"); await page.waitForChanges(); expect(await dropdownWrapper.isVisible()).toBe(true); + await waitForCalciteDropdownOpen; + expect(calciteDropdownOpen).toHaveReceivedEventTimes(2); + expect(calciteDropdownClose).toHaveReceivedEventTimes(1); }); - it("closes when close-on-select-disabled is requested and selected item is in a selection-mode:none group", async () => { + it("toggle when trigger is an action", async () => { const page = await newE2EPage(); - await page.setContent(html` - Open dropdown - - -
Dropdown Item Content
-
- Dropdown Item Content - Dropdown Item Content -
-
`); - + await page.setContent(html` + + Open dropdown + + Dropdown Item Content + Dropdown Item Content + + + `); const element = await page.find("calcite-dropdown"); - const trigger = await element.find("#trigger"); - const item1 = await element.find("#item-1"); - const dropdownWrapper = await page.find("calcite-dropdown >>> .calcite-dropdown-wrapper"); + const trigger = await element.find("calcite-action[slot='trigger'] >>> button"); + const dropdownWrapper = await page.find(`calcite-dropdown >>> .calcite-dropdown-wrapper`); + const calciteDropdownOpen = await element.spyOnEvent("calciteDropdownOpen"); + const calciteDropdownClose = await element.spyOnEvent("calciteDropdownClose"); + let waitForCalciteDropdownOpen = page.waitForEvent("calciteDropdownOpen"); + const waitForCalciteDropdownClose = page.waitForEvent("calciteDropdownClose"); + expect(await dropdownWrapper.isVisible()).toBe(false); await trigger.click(); await page.waitForChanges(); expect(await dropdownWrapper.isVisible()).toBe(true); - await item1.click(); + await waitForCalciteDropdownOpen; + expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); + expect(calciteDropdownClose).toHaveReceivedEventTimes(0); + + await element.callMethod("setFocus"); + await page.waitForChanges(); + await page.keyboard.press("Space"); await page.waitForChanges(); expect(await dropdownWrapper.isVisible()).toBe(false); - }); - - describe("toggles the dropdown with click, enter, or space", () => { - it("toggles when trigger is a button", async () => { - const page = await newE2EPage(); - await page.setContent(html` - - Open dropdown - - Dropdown Item Content - Dropdown Item Content - - - `); - const element = await page.find("calcite-dropdown"); - const trigger = await element.find("calcite-button[slot='trigger']"); - const dropdownWrapper = await page.find(`calcite-dropdown >>> .calcite-dropdown-wrapper`); - const calciteDropdownOpen = await element.spyOnEvent("calciteDropdownOpen"); - const calciteDropdownClose = await element.spyOnEvent("calciteDropdownClose"); - let waitForCalciteDropdownOpen = page.waitForEvent("calciteDropdownOpen"); - const waitForCalciteDropdownClose = page.waitForEvent("calciteDropdownClose"); - - expect(await dropdownWrapper.isVisible()).toBe(false); - await trigger.click(); - await page.waitForChanges(); - expect(await dropdownWrapper.isVisible()).toBe(true); - await waitForCalciteDropdownOpen; - expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); - expect(calciteDropdownClose).toHaveReceivedEventTimes(0); - - await element.callMethod("setFocus"); - await page.waitForChanges(); - await page.keyboard.press("Space"); - await page.waitForChanges(); - expect(await dropdownWrapper.isVisible()).toBe(false); - await waitForCalciteDropdownClose; - expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); - expect(calciteDropdownClose).toHaveReceivedEventTimes(1); - - waitForCalciteDropdownOpen = page.waitForEvent("calciteDropdownOpen"); - - await page.keyboard.press("Enter"); - await page.waitForChanges(); - expect(await dropdownWrapper.isVisible()).toBe(true); - await waitForCalciteDropdownOpen; - expect(calciteDropdownOpen).toHaveReceivedEventTimes(2); - expect(calciteDropdownClose).toHaveReceivedEventTimes(1); - }); - - it("toggle when trigger is an action", async () => { - const page = await newE2EPage(); - await page.setContent(html` - - Open dropdown - - Dropdown Item Content - Dropdown Item Content - - - `); - const element = await page.find("calcite-dropdown"); - const trigger = await element.find("calcite-action[slot='trigger'] >>> button"); - const dropdownWrapper = await page.find(`calcite-dropdown >>> .calcite-dropdown-wrapper`); - const calciteDropdownOpen = await element.spyOnEvent("calciteDropdownOpen"); - const calciteDropdownClose = await element.spyOnEvent("calciteDropdownClose"); - let waitForCalciteDropdownOpen = page.waitForEvent("calciteDropdownOpen"); - const waitForCalciteDropdownClose = page.waitForEvent("calciteDropdownClose"); - - expect(await dropdownWrapper.isVisible()).toBe(false); - await trigger.click(); - await page.waitForChanges(); - expect(await dropdownWrapper.isVisible()).toBe(true); - await waitForCalciteDropdownOpen; - expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); - expect(calciteDropdownClose).toHaveReceivedEventTimes(0); - - await element.callMethod("setFocus"); - await page.waitForChanges(); - await page.keyboard.press("Space"); - await page.waitForChanges(); - expect(await dropdownWrapper.isVisible()).toBe(false); - await waitForCalciteDropdownClose; - expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); - expect(calciteDropdownClose).toHaveReceivedEventTimes(1); - - waitForCalciteDropdownOpen = page.waitForEvent("calciteDropdownOpen"); - - await page.keyboard.press("Enter"); - await page.waitForChanges(); - expect(await dropdownWrapper.isVisible()).toBe(true); - await waitForCalciteDropdownOpen; - expect(calciteDropdownOpen).toHaveReceivedEventTimes(2); - expect(calciteDropdownClose).toHaveReceivedEventTimes(1); - }); - - it("toggles when Enter keydown is dispatched", async () => { - const page = await newE2EPage(); - await page.setContent(html` - - Open dropdown - - Dropdown Item Content - Dropdown Item Content - - - `); - const element = await page.find("calcite-dropdown"); - const dropdownWrapper = await page.find(`calcite-dropdown >>> .calcite-dropdown-wrapper`); - const calciteDropdownOpen = await element.spyOnEvent("calciteDropdownOpen"); - const calciteDropdownClose = await element.spyOnEvent("calciteDropdownClose"); - const waitForCalciteDropdownOpen = page.waitForEvent("calciteDropdownOpen"); - - expect(await dropdownWrapper.isVisible()).toBe(false); - - await page.$eval("calcite-button[slot='trigger']", (triggerEl: HTMLCalciteButtonElement) => { - // intentionally not pressing to avoid emitting `click` - triggerEl.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true })); - }); - - await page.waitForChanges(); - expect(await dropdownWrapper.isVisible()).toBe(true); - await waitForCalciteDropdownOpen; - expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); - expect(calciteDropdownClose).toHaveReceivedEventTimes(0); - }); - }); + await waitForCalciteDropdownClose; + expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); + expect(calciteDropdownClose).toHaveReceivedEventTimes(1); - describe("Focus order with Tab key", () => { - it("closes dropdown and focuses the next focusable element on Tab", async () => { - const page = await newE2EPage(); - await page.setContent(html` - - Open dropdown - - Dropdown Item Content - Dropdown Item Content - - - Click - `); - const element = await page.find("calcite-dropdown"); - const trigger = await element.find("calcite-action[slot='trigger'] >>> button"); - const dropdownWrapper = await page.find(`calcite-dropdown >>> .calcite-dropdown-wrapper`); - const calciteDropdownClose = await element.spyOnEvent("calciteDropdownClose"); - const calciteDropdownOpen = await element.spyOnEvent("calciteDropdownOpen"); - - expect(await dropdownWrapper.isVisible()).toBe(false); - await trigger.click(); - await page.waitForChanges(); - expect(await dropdownWrapper.isVisible()).toBe(true); - expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); - expect(calciteDropdownClose).toHaveReceivedEventTimes(0); - expect(await getFocusedElementProp(page, "id")).toBe("item-2"); - - await element.press("Tab"); - await page.waitForChanges(); - expect(await getFocusedElementProp(page, "id")).toBe("button-1"); - expect(calciteDropdownClose).toHaveReceivedEventTimes(1); - expect(await dropdownWrapper.isVisible()).toBe(false); - }); + waitForCalciteDropdownOpen = page.waitForEvent("calciteDropdownOpen"); - it("closes dropdown and focuses the trigger on Shift+Tab", async () => { - const page = await newE2EPage(); - await page.setContent(html` - - Open dropdown - - Dropdown Item Content - Dropdown Item Content - - - Click - `); - const element = await page.find("calcite-dropdown"); - const trigger = await element.find("calcite-action[slot='trigger'] >>> button"); - const dropdownWrapper = await page.find(`calcite-dropdown >>> .calcite-dropdown-wrapper`); - const calciteDropdownClose = await element.spyOnEvent("calciteDropdownClose"); - const calciteDropdownOpen = await element.spyOnEvent("calciteDropdownOpen"); - - expect(await dropdownWrapper.isVisible()).toBe(false); - await trigger.click(); - await page.waitForChanges(); - expect(await dropdownWrapper.isVisible()).toBe(true); - expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); - expect(calciteDropdownClose).toHaveReceivedEventTimes(0); - expect(await getFocusedElementProp(page, "id")).toBe("item-2"); - - await page.keyboard.down("Shift"); - await element.press("Tab"); - await page.keyboard.up("Shift"); - await page.waitForChanges(); - expect(await getFocusedElementProp(page, "id")).toBe("trigger"); - expect(calciteDropdownClose).toHaveReceivedEventTimes(1); - expect(await dropdownWrapper.isVisible()).toBe(false); - }); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + expect(await dropdownWrapper.isVisible()).toBe(true); + await waitForCalciteDropdownOpen; + expect(calciteDropdownOpen).toHaveReceivedEventTimes(2); + expect(calciteDropdownClose).toHaveReceivedEventTimes(1); }); - it("closes existing open dropdown when opened", async () => { + it("toggles when Enter keydown is dispatched", async () => { const page = await newE2EPage(); - await page.setContent(html` - Open dropdown - + await page.setContent(html` + + Open dropdown + Dropdown Item Content Dropdown Item Content - Dropdown Item Content - - Open dropdown - - Dropdown Item Content - Dropdown Item Content - Dropdown Item Content - - `); - - const element1 = await page.find("calcite-dropdown[id='dropdown-1']"); - const element2 = await page.find("calcite-dropdown[id='dropdown-2']"); - const trigger1 = await element1.find("#trigger"); - const trigger2 = await element2.find("#trigger"); - const dropdownWrapper1 = await page.find("calcite-dropdown[id='dropdown-1'] >>> .calcite-dropdown-wrapper"); - const dropdownWrapper2 = await page.find("calcite-dropdown[id='dropdown-2'] >>> .calcite-dropdown-wrapper"); - expect(await dropdownWrapper1.isVisible()).toBe(false); - expect(await dropdownWrapper2.isVisible()).toBe(false); - await trigger1.click(); - await page.waitForChanges(); - expect(await dropdownWrapper1.isVisible()).toBe(true); - expect(await dropdownWrapper2.isVisible()).toBe(false); - await trigger2.click(); + `); + const element = await page.find("calcite-dropdown"); + const dropdownWrapper = await page.find(`calcite-dropdown >>> .calcite-dropdown-wrapper`); + const calciteDropdownOpen = await element.spyOnEvent("calciteDropdownOpen"); + const calciteDropdownClose = await element.spyOnEvent("calciteDropdownClose"); + const waitForCalciteDropdownOpen = page.waitForEvent("calciteDropdownOpen"); + + expect(await dropdownWrapper.isVisible()).toBe(false); + + await page.$eval("calcite-button[slot='trigger']", (triggerEl: HTMLCalciteButtonElement) => { + // intentionally not pressing to avoid emitting `click` + triggerEl.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true })); + }); + await page.waitForChanges(); - expect(await dropdownWrapper1.isVisible()).toBe(false); - expect(await dropdownWrapper2.isVisible()).toBe(true); + expect(await dropdownWrapper.isVisible()).toBe(true); + await waitForCalciteDropdownOpen; + expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); + expect(calciteDropdownClose).toHaveReceivedEventTimes(0); }); + }); - it("focus is returned to trigger after close", async () => { + describe("Focus order with Tab key", () => { + it("closes dropdown and focuses the next focusable element on Tab", async () => { const page = await newE2EPage(); await page.setContent(html` - Open dropdown - - Dropdown Item Content - Dropdown Item Content - Dropdown Item Content + Open dropdown + + Dropdown Item Content + Dropdown Item Content + Click `); - const element = await page.find("calcite-dropdown"); - const trigger = await element.find("#trigger"); - const item1 = await element.find("calcite-dropdown-item[id='item-1']"); - const dropdownWrapper = await page.find("calcite-dropdown >>> .calcite-dropdown-wrapper"); + const trigger = await element.find("calcite-action[slot='trigger'] >>> button"); + const dropdownWrapper = await page.find(`calcite-dropdown >>> .calcite-dropdown-wrapper`); + const calciteDropdownClose = await element.spyOnEvent("calciteDropdownClose"); + const calciteDropdownOpen = await element.spyOnEvent("calciteDropdownOpen"); + expect(await dropdownWrapper.isVisible()).toBe(false); await trigger.click(); await page.waitForChanges(); expect(await dropdownWrapper.isVisible()).toBe(true); - await item1.click(); + expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); + expect(calciteDropdownClose).toHaveReceivedEventTimes(0); + expect(await getFocusedElementProp(page, "id")).toBe("item-2"); + + await element.press("Tab"); await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("button-1"); + expect(calciteDropdownClose).toHaveReceivedEventTimes(1); expect(await dropdownWrapper.isVisible()).toBe(false); - expect(await page.evaluate(() => document.activeElement.id)).toEqual("trigger"); }); - it("accepts multiple triggers", async () => { + it("closes dropdown and focuses the trigger on Shift+Tab", async () => { const page = await newE2EPage(); await page.setContent(html` - Open dropdown - - - Dropdown Item Content - Dropdown Item Content - Dropdown Item Content + Open dropdown + + Dropdown Item Content + Dropdown Item Content + Click `); - const element = await page.find("calcite-dropdown"); - const trigger = await element.findAll(".trigger"); - const dropdownWrapper = await page.find("calcite-dropdown >>> .calcite-dropdown-wrapper"); - await trigger[0].click(); - expect(await dropdownWrapper.isVisible()).toBe(true); - await trigger[0].click(); - await page.waitForChanges(); + const trigger = await element.find("calcite-action[slot='trigger'] >>> button"); + const dropdownWrapper = await page.find(`calcite-dropdown >>> .calcite-dropdown-wrapper`); + const calciteDropdownClose = await element.spyOnEvent("calciteDropdownClose"); + const calciteDropdownOpen = await element.spyOnEvent("calciteDropdownOpen"); + expect(await dropdownWrapper.isVisible()).toBe(false); + await trigger.click(); await page.waitForChanges(); - await trigger[1].click(); expect(await dropdownWrapper.isVisible()).toBe(true); - await trigger[1].click(); + expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); + expect(calciteDropdownClose).toHaveReceivedEventTimes(0); + expect(await getFocusedElementProp(page, "id")).toBe("item-2"); + + await page.keyboard.down("Shift"); + await element.press("Tab"); + await page.keyboard.up("Shift"); await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("trigger"); + expect(calciteDropdownClose).toHaveReceivedEventTimes(1); expect(await dropdownWrapper.isVisible()).toBe(false); }); + }); - describe("accessible", () => { - accessible(dedent`${dropdownSelectionModeContent}`); - }); + it("closes existing open dropdown when opened", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Open dropdown + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + + + Open dropdown + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + `); - it("correct role and aria properties are applied based on selection type", async () => { - const page = await newE2EPage(); - await page.setContent(dedent`${dropdownSelectionModeContent}`); - await page.waitForChanges(); + const element1 = await page.find("calcite-dropdown[id='dropdown-1']"); + const element2 = await page.find("calcite-dropdown[id='dropdown-2']"); + const trigger1 = await element1.find("#trigger"); + const trigger2 = await element2.find("#trigger"); + const dropdownWrapper1 = await page.find("calcite-dropdown[id='dropdown-1'] >>> .calcite-dropdown-wrapper"); + const dropdownWrapper2 = await page.find("calcite-dropdown[id='dropdown-2'] >>> .calcite-dropdown-wrapper"); + expect(await dropdownWrapper1.isVisible()).toBe(false); + expect(await dropdownWrapper2.isVisible()).toBe(false); + await trigger1.click(); + await page.waitForChanges(); + expect(await dropdownWrapper1.isVisible()).toBe(true); + expect(await dropdownWrapper2.isVisible()).toBe(false); + await trigger2.click(); + await page.waitForChanges(); + expect(await dropdownWrapper1.isVisible()).toBe(false); + expect(await dropdownWrapper2.isVisible()).toBe(true); + }); - const element = await page.find("calcite-dropdown"); - const group1 = await element.find("calcite-dropdown-group[id='group-1']"); - const group2 = await element.find("calcite-dropdown-group[id='group-2']"); - const group3 = await element.find("calcite-dropdown-group[id='group-3']"); - const item1 = await element.find("calcite-dropdown-item[id='item-1']"); - const item2 = await element.find("calcite-dropdown-item[id='item-2']"); - const item3 = await element.find("calcite-dropdown-item[id='item-3']"); - const item4 = await element.find("calcite-dropdown-item[id='item-4']"); - const item5 = await element.find("calcite-dropdown-item[id='item-5']"); - const item6 = await element.find("calcite-dropdown-item[id='item-6']"); - const item7 = await element.find("calcite-dropdown-item[id='item-7']"); + it("focus is returned to trigger after close", async () => { + const page = await newE2EPage(); + await page.setContent(html` + + Open dropdown + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + + `); + + const element = await page.find("calcite-dropdown"); + const trigger = await element.find("#trigger"); + const item1 = await element.find("calcite-dropdown-item[id='item-1']"); + const dropdownWrapper = await page.find("calcite-dropdown >>> .calcite-dropdown-wrapper"); + expect(await dropdownWrapper.isVisible()).toBe(false); + await trigger.click(); + await page.waitForChanges(); + expect(await dropdownWrapper.isVisible()).toBe(true); + await item1.click(); + await page.waitForChanges(); + expect(await dropdownWrapper.isVisible()).toBe(false); + expect(await page.evaluate(() => document.activeElement.id)).toEqual("trigger"); + }); + + it("accepts multiple triggers", async () => { + const page = await newE2EPage(); + await page.setContent(html` + + Open dropdown + + + Dropdown Item Content + Dropdown Item Content + Dropdown Item Content + + + `); + + const element = await page.find("calcite-dropdown"); + const trigger = await element.findAll(".trigger"); + const dropdownWrapper = await page.find("calcite-dropdown >>> .calcite-dropdown-wrapper"); + await trigger[0].click(); + expect(await dropdownWrapper.isVisible()).toBe(true); + await trigger[0].click(); + await page.waitForChanges(); + expect(await dropdownWrapper.isVisible()).toBe(false); + await page.waitForChanges(); + await trigger[1].click(); + expect(await dropdownWrapper.isVisible()).toBe(true); + await trigger[1].click(); + await page.waitForChanges(); + expect(await dropdownWrapper.isVisible()).toBe(false); + }); - expect(group1).toEqualAttribute("role", "group"); - expect(group2).toEqualAttribute("role", "group"); - expect(group3).toEqualAttribute("role", "group"); + describe("accessible", () => { + accessible(dedent`${dropdownSelectionModeContent}`); + }); - expect(item1).toEqualAttribute("role", "menuitemcheckbox"); - expect(item1).toEqualAttribute("aria-checked", "false"); + it("correct role and aria properties are applied based on selection type", async () => { + const page = await newE2EPage(); + await page.setContent(dedent`${dropdownSelectionModeContent}`); + await page.waitForChanges(); - expect(item2).toEqualAttribute("role", "menuitemcheckbox"); - expect(item2).toEqualAttribute("aria-checked", "true"); + const element = await page.find("calcite-dropdown"); + const group1 = await element.find("calcite-dropdown-group[id='group-1']"); + const group2 = await element.find("calcite-dropdown-group[id='group-2']"); + const group3 = await element.find("calcite-dropdown-group[id='group-3']"); + const item1 = await element.find("calcite-dropdown-item[id='item-1']"); + const item2 = await element.find("calcite-dropdown-item[id='item-2']"); + const item3 = await element.find("calcite-dropdown-item[id='item-3']"); + const item4 = await element.find("calcite-dropdown-item[id='item-4']"); + const item5 = await element.find("calcite-dropdown-item[id='item-5']"); + const item6 = await element.find("calcite-dropdown-item[id='item-6']"); + const item7 = await element.find("calcite-dropdown-item[id='item-7']"); - expect(item3).toEqualAttribute("role", "menuitemcheckbox"); - expect(item3).toEqualAttribute("aria-checked", "true"); + expect(group1).toEqualAttribute("role", "group"); + expect(group2).toEqualAttribute("role", "group"); + expect(group3).toEqualAttribute("role", "group"); - expect(item4).toEqualAttribute("role", "menuitemradio"); - expect(item4).toEqualAttribute("aria-checked", "false"); + expect(item1).toEqualAttribute("role", "menuitemcheckbox"); + expect(item1).toEqualAttribute("aria-checked", "false"); - expect(item5).toEqualAttribute("role", "menuitemradio"); - expect(item5).toEqualAttribute("aria-checked", "true"); + expect(item2).toEqualAttribute("role", "menuitemcheckbox"); + expect(item2).toEqualAttribute("aria-checked", "true"); - expect(item6).toEqualAttribute("role", "menuitem"); - expect(item6).not.toHaveAttribute("aria-checked"); + expect(item3).toEqualAttribute("role", "menuitemcheckbox"); + expect(item3).toEqualAttribute("aria-checked", "true"); - expect(item7).not.toHaveAttribute("role"); - expect(item7).not.toHaveAttribute("aria-checked"); - }); + expect(item4).toEqualAttribute("role", "menuitemradio"); + expect(item4).toEqualAttribute("aria-checked", "false"); - it("item selection should work when placed inside shadow DOM (#992)", async () => { - const wrappedDropdownTemplateHTML = html` - - Open - - 1 - 2 - 3 - - - `; + expect(item5).toEqualAttribute("role", "menuitemradio"); + expect(item5).toEqualAttribute("aria-checked", "true"); - const page = await newE2EPage({ - // load page with the dropdown template, - // so they're available in the browser-evaluated fn below - html: wrappedDropdownTemplateHTML, - }); - await page.waitForChanges(); + expect(item6).toEqualAttribute("role", "menuitem"); + expect(item6).not.toHaveAttribute("aria-checked"); + + expect(item7).not.toHaveAttribute("role"); + expect(item7).not.toHaveAttribute("aria-checked"); + }); + + it("item selection should work when placed inside shadow DOM (#992)", async () => { + const wrappedDropdownTemplateHTML = html` + + Open + + 1 + 2 + 3 + + + `; - const wrapperName = "dropdown-wrapping-component"; + const page = await newE2EPage({ + // load page with the dropdown template, + // so they're available in the browser-evaluated fn below + html: wrappedDropdownTemplateHTML, + }); + await page.waitForChanges(); - await page.evaluate( - async (templateHTML: string, wrapperName: string): Promise => { - customElements.define( - wrapperName, - class extends HTMLElement { - constructor() { - super(); - } + const wrapperName = "dropdown-wrapping-component"; - connectedCallback(): void { - this.attachShadow({ mode: "open" }).innerHTML = templateHTML; - } + await page.evaluate( + async (templateHTML: string, wrapperName: string): Promise => { + customElements.define( + wrapperName, + class extends HTMLElement { + constructor() { + super(); } - ); - - document.body.innerHTML = `<${wrapperName}>`; - const wrapper = document.querySelector(wrapperName); - wrapper.shadowRoot.querySelector("#item-3").click(); - }, - wrappedDropdownTemplateHTML, - wrapperName - ); + connectedCallback(): void { + this.attachShadow({ mode: "open" }).innerHTML = templateHTML; + } + } + ); - await page.waitForChanges(); + document.body.innerHTML = `<${wrapperName}>`; - const finalSelectedItem = await page.evaluate(async (wrapperName: string): Promise => { const wrapper = document.querySelector(wrapperName); - return wrapper.shadowRoot.querySelector("calcite-dropdown-item[selected]").id; - }, wrapperName); - - await expect(finalSelectedItem).toBe("item-3"); - }); + wrapper.shadowRoot.querySelector("#item-3").click(); + }, + wrappedDropdownTemplateHTML, + wrapperName + ); - it.skip("dropdown should not overflow when wrapped inside a tab #3007", async () => { - const page = await newE2EPage({ - html: html` - - First tab - - - - Dropdown - - First - Second - - - - `, - }); - await page.waitForChanges(); + await page.waitForChanges(); - const button = await page.find("calcite-button"); + const finalSelectedItem = await page.evaluate(async (wrapperName: string): Promise => { + const wrapper = document.querySelector(wrapperName); + return wrapper.shadowRoot.querySelector("calcite-dropdown-item[selected]").id; + }, wrapperName); - await button.click(); - await page.waitForChanges(); + await expect(finalSelectedItem).toBe("item-3"); + }); - expect( - await page.$eval("calcite-dropdown", (dropdown) => { - // check whether the element is overflown, ref :https://stackoverflow.com/questions/9333379/check-if-an-elements-content-is-overflowing - const { clientWidth, clientHeight, scrollWidth, scrollHeight } = dropdown; - return scrollHeight > clientHeight || scrollWidth > clientWidth; - }) - ).toBe(false); + it.skip("dropdown should not overflow when wrapped inside a tab #3007", async () => { + const page = await newE2EPage({ + html: html` + + First tab + + + + Dropdown + + First + Second + + + + `, }); + await page.waitForChanges(); - it("dropdown wrapper should have height when filter results empty and combined with a PickList in Panel #3048", async () => { - const page = await newE2EPage({ - html: html` - - - - - Display name - Type - - - - - - `, - }); - await page.waitForChanges(); - - const dropdownContentHeight = await ( - await page.find("calcite-dropdown >>> .calcite-dropdown-wrapper") - ).getComputedStyle(); + const button = await page.find("calcite-button"); - await page.evaluate(() => { - const filter = document.querySelector(`calcite-pick-list`).shadowRoot.querySelector("calcite-filter"); - const filterInput = filter.shadowRoot.querySelector("calcite-input"); - filterInput.value = "numbers"; - }); + await button.click(); + await page.waitForChanges(); - expect(dropdownContentHeight.height).toBe("88px"); - }); + expect( + await page.$eval("calcite-dropdown", (dropdown) => { + // check whether the element is overflown, ref :https://stackoverflow.com/questions/9333379/check-if-an-elements-content-is-overflowing + const { clientWidth, clientHeight, scrollWidth, scrollHeight } = dropdown; + return scrollHeight > clientHeight || scrollWidth > clientWidth; + }) + ).toBe(false); + }); - describe("owns a floating-ui", () => { - floatingUIOwner( - html` - - Open + it("dropdown wrapper should have height when filter results empty and combined with a PickList in Panel #3048", async () => { + const page = await newE2EPage({ + html: html` + + + - 1 - 2 - 3 + Display name + Type - `, - "open", - { - shadowSelector: ".calcite-dropdown-wrapper", - } - ); + + + + `, + }); + await page.waitForChanges(); + + const dropdownContentHeight = await ( + await page.find("calcite-dropdown >>> .calcite-dropdown-wrapper") + ).getComputedStyle(); + + await page.evaluate(() => { + const filter = document.querySelector(`calcite-pick-list`).shadowRoot.querySelector("calcite-filter"); + const filterInput = filter.shadowRoot.querySelector("calcite-input"); + filterInput.value = "numbers"; }); + + expect(dropdownContentHeight.height).toBe("88px"); + }); + + describe("owns a floating-ui", () => { + floatingUIOwner( + html` + + Open + + 1 + 2 + 3 + + + `, + "open", + { + shadowSelector: ".calcite-dropdown-wrapper", + } + ); }); });