diff --git a/packages/calcite-components/eslint.config.mjs b/packages/calcite-components/eslint.config.mjs index 0e73115b3d8..3e9bc422520 100644 --- a/packages/calcite-components/eslint.config.mjs +++ b/packages/calcite-components/eslint.config.mjs @@ -48,6 +48,10 @@ export default tseslint.config( property: "findAll", message: "Use custom findAll test util for more predictable (non-empty) result usage.", }, + { + property: "waitForEvent", + message: "Use spyOnEvent and await on its next property instead for more reliable async event handling.", + }, ], "unused-imports/no-unused-imports": "error", diff --git a/packages/calcite-components/src/components/action-bar/action-bar.e2e.ts b/packages/calcite-components/src/components/action-bar/action-bar.e2e.ts index c4dcc532a9d..2f59f14f9b5 100755 --- a/packages/calcite-components/src/components/action-bar/action-bar.e2e.ts +++ b/packages/calcite-components/src/components/action-bar/action-bar.e2e.ts @@ -375,17 +375,14 @@ describe("calcite-action-bar", () => { expect(await groups[0].getProperty("menuOpen")).toBe(false); expect(await groups[1].getProperty("menuOpen")).toBe(true); - const calciteActionMenuOpenEvent = page.waitForEvent("calciteActionMenuOpen"); - + const calciteActionMenuOpenEventSpy = await page.spyOnEvent("calciteActionMenuOpen"); await page.$eval("calcite-action-group", (firstActionGroup: ActionGroup["el"]) => { firstActionGroup.menuOpen = true; const event = new CustomEvent("calciteActionMenuOpen", { bubbles: true }); firstActionGroup.dispatchEvent(event); }); - - await calciteActionMenuOpenEvent; - await page.waitForChanges(); + await calciteActionMenuOpenEventSpy.next(); expect(groups).toHaveLength(2); expect(await groups[0].getProperty("menuOpen")).toBe(true); diff --git a/packages/calcite-components/src/components/action-menu/action-menu.e2e.ts b/packages/calcite-components/src/components/action-menu/action-menu.e2e.ts index ffd2b0391e2..dc3c06ba0d8 100755 --- a/packages/calcite-components/src/components/action-menu/action-menu.e2e.ts +++ b/packages/calcite-components/src/components/action-menu/action-menu.e2e.ts @@ -14,7 +14,7 @@ import { themed, } from "../../tests/commonTests"; import { CSS as TooltipCSS, TOOLTIP_OPEN_DELAY_MS } from "../tooltip/resources"; -import { findAll, isElementFocused, skipAnimations } from "../../tests/utils/puppeteer"; +import { findAll, isElementFocused, skipAnimations, waitForAnimationFrame } from "../../tests/utils/puppeteer"; import type { Action } from "../action/action"; import { mockConsole } from "../../tests/utils/logging"; import { activeAttr, CSS, SLOTS } from "./resources"; @@ -111,21 +111,20 @@ describe("calcite-action-menu", () => { }); it("should emit 'calciteActionMenuOpen' event", async () => { - const page = await newE2EPage({ - html: ` - - `, - }); - - await page.waitForChanges(); - + const page = await newE2EPage(); + await page.setContent( + html` + + `, + ); + await skipAnimations(page); const clickSpy = await page.spyOnEvent("calciteActionMenuOpen"); - const actionMenu = await page.find("calcite-action-menu"); + const openEventSpy = await actionMenu.spyOnEvent("calciteActionMenuOpen"); actionMenu.setProperty("open", true); - await page.waitForChanges(); + await openEventSpy.next(); expect(clickSpy).toHaveReceivedEventTimes(1); }); @@ -145,45 +144,49 @@ describe("calcite-action-menu", () => { ); }); + async function waitForActionMenuClose(page: E2EPage): Promise { + // replace with close event handling once https://github.com/Esri/calcite-design-system/issues/4544 lands + await page.waitForFunction(() => document.querySelector("calcite-action-menu").open === false); + } + it("should close menu if clicked outside", async () => { - const page = await newE2EPage({ - html: ` - - - - -
+ const page = await newE2EPage(); + await page.setContent(html` + + + + + +
-
`, - }); - - await page.waitForChanges(); - +
+ `); + await skipAnimations(page); const actionMenu = await page.find("calcite-action-menu"); - const popover = await page.find("calcite-action-menu >>> calcite-popover"); + const outside = await page.find("#outside"); - expect(await popover.getProperty("autoClose")).toBe(true); + const openEventSpy = await actionMenu.spyOnEvent("calciteActionMenuOpen"); + actionMenu.setProperty("open", true); + await page.waitForChanges(); + await openEventSpy.next(); + expect(await popover.getProperty("autoClose")).toBe(true); expect(await popover.getProperty("open")).toBe(true); - expect(await actionMenu.getProperty("open")).toBe(true); - const outside = await page.find("#outside"); - await outside.click(); - await page.waitForChanges(); + await waitForActionMenuClose(page); expect(await actionMenu.getProperty("open")).toBe(false); - expect(await popover.getProperty("open")).toBe(false); }); it("should close menu if slotted action is clicked", async () => { const page = await newE2EPage(); await page.setContent(html` - + @@ -193,11 +196,17 @@ describe("calcite-action-menu", () => { await page.waitForChanges(); const actionMenu = await page.find("calcite-action-menu"); + const openEventSpy = await actionMenu.spyOnEvent("calciteActionMenuOpen"); + actionMenu.setProperty("open", true); + await page.waitForChanges(); + await openEventSpy.next(); + expect(await actionMenu.getProperty("open")).toBe(true); const action = await page.find("#slottedAction"); await action.click(); await page.waitForChanges(); + await waitForActionMenuClose(page); expect(await actionMenu.getProperty("open")).toBe(false); @@ -254,7 +263,6 @@ describe("calcite-action-menu", () => { it("should honor scale of expand icon", async () => { const page = await newE2EPage({ html: `` }); - const trigger = await page.find(`calcite-action-menu >>> .${CSS.defaultTrigger}`); expect(await trigger.getProperty("scale")).toBe("l"); @@ -262,7 +270,6 @@ describe("calcite-action-menu", () => { it("should close tooltip when open", async () => { const page = await newE2EPage(); - await page.setContent(html` @@ -270,9 +277,7 @@ describe("calcite-action-menu", () => { `); - await skipAnimations(page); - const actionMenu = await page.find("calcite-action-menu"); const tooltipPositionContainer = await page.find(`calcite-tooltip >>> .${TooltipCSS.positionContainer}`); const trigger = await page.find("#trigger"); @@ -284,15 +289,16 @@ describe("calcite-action-menu", () => { expect(await tooltipPositionContainer.isVisible()).toBe(true); + const openEventSpy = await actionMenu.spyOnEvent("calciteActionMenuOpen"); actionMenu.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); expect(await tooltipPositionContainer.isVisible()).toBe(false); }); it("should stop propagation of popover events", async () => { const page = await newE2EPage(); - await page.setContent(html` @@ -300,7 +306,6 @@ describe("calcite-action-menu", () => { `); - await skipAnimations(page); const actionMenu = await page.find("calcite-action-menu"); @@ -310,13 +315,15 @@ describe("calcite-action-menu", () => { const popoverOpen = await actionMenu.spyOnEvent("calcitePopoverOpen"); const popoverClose = await actionMenu.spyOnEvent("calcitePopoverClose"); + const openEventSpy = await actionMenu.spyOnEvent("calciteActionMenuOpen"); await trigger.click(); - await page.waitForChanges(); + await openEventSpy.next(); expect(await actionMenu.getProperty("open")).toBe(true); await outside.click(); await page.waitForChanges(); + await waitForActionMenuClose(page); expect(await actionMenu.getProperty("open")).toBe(false); @@ -326,16 +333,15 @@ describe("calcite-action-menu", () => { describe("Keyboard navigation", () => { it("should handle ArrowDown navigation", async () => { - const page = await newE2EPage({ - html: html` + const page = await newE2EPage(); + await page.setContent(html` + - `, - }); - - await page.waitForChanges(); - + + `); + await skipAnimations(page); const actionMenu = await page.find("calcite-action-menu"); const actions = await findAll(page, "calcite-action"); const trigger = await page.find(`calcite-action-menu >>> .${CSS.defaultTrigger}`); @@ -344,10 +350,10 @@ describe("calcite-action-menu", () => { await actionMenu.callMethod("setFocus"); await page.waitForChanges(); - + const openEventSpy = await actionMenu.spyOnEvent("calciteActionMenuOpen"); await page.keyboard.press("ArrowDown"); - await page.waitForTimeout(0); await page.waitForChanges(); + await openEventSpy.next(); expect(await trigger.getProperty("active")).toBe(true); expect(await actionMenu.getProperty("open")).toBe(true); @@ -356,7 +362,7 @@ describe("calcite-action-menu", () => { expect(actions[2].getAttribute(activeAttr)).toBe(null); await page.keyboard.press("ArrowDown"); - await page.waitForTimeout(0); + await waitForAnimationFrame(page); await page.waitForChanges(); expect(actions[0].getAttribute(activeAttr)).toBe(null); @@ -365,17 +371,16 @@ describe("calcite-action-menu", () => { }); it("should handle ArrowDown navigation with disabled/hidden items", async () => { - const page = await newE2EPage({ - html: html` + const page = await newE2EPage(); + await page.setContent(html` + - `, - }); - - await page.waitForChanges(); - + + `); + await skipAnimations(page); const actionMenu = await page.find("calcite-action-menu"); const actions = await findAll(page, "calcite-action"); const trigger = await page.find(`calcite-action-menu >>> .${CSS.defaultTrigger}`); @@ -384,9 +389,10 @@ describe("calcite-action-menu", () => { await actionMenu.callMethod("setFocus"); await page.waitForChanges(); - + const openEventSpy = await actionMenu.spyOnEvent("calciteActionMenuOpen"); await page.keyboard.press("ArrowDown"); await page.waitForChanges(); + await openEventSpy.next(); expect(await trigger.getProperty("active")).toBe(true); expect(await actionMenu.getProperty("open")).toBe(true); @@ -396,6 +402,7 @@ describe("calcite-action-menu", () => { expect(actions[3].getAttribute(activeAttr)).toBe(null); await page.keyboard.press("ArrowDown"); + await waitForAnimationFrame(page); await page.waitForChanges(); expect(actions[0].getAttribute(activeAttr)).toBe(null); @@ -405,16 +412,15 @@ describe("calcite-action-menu", () => { }); it("should handle ArrowUp navigation", async () => { - const page = await newE2EPage({ - html: html` + const page = await newE2EPage(); + await page.setContent( + html` - `, - }); - - await page.waitForChanges(); - + `, + ); + await skipAnimations(page); const actionMenu = await page.find("calcite-action-menu"); const actions = await findAll(page, "calcite-action"); const trigger = await page.find(`calcite-action-menu >>> .${CSS.defaultTrigger}`); @@ -424,10 +430,10 @@ describe("calcite-action-menu", () => { await actionMenu.callMethod("setFocus"); await page.waitForChanges(); - + const openEventSpy = await actionMenu.spyOnEvent("calciteActionMenuOpen"); await page.keyboard.press("ArrowUp"); - await page.waitForTimeout(0); await page.waitForChanges(); + await openEventSpy.next(); expect(await trigger.getProperty("active")).toBe(true); expect(await actionMenu.getProperty("open")).toBe(true); @@ -436,7 +442,7 @@ describe("calcite-action-menu", () => { expect(actions[2].getAttribute(activeAttr)).toBe(""); await page.keyboard.press("ArrowUp"); - await page.waitForTimeout(0); + await waitForAnimationFrame(page); await page.waitForChanges(); expect(actions[0].getAttribute(activeAttr)).toBe(null); @@ -445,16 +451,15 @@ describe("calcite-action-menu", () => { }); it("should handle Enter, Home, End and ESC navigation", async () => { - const page = await newE2EPage({ - html: html` + const page = await newE2EPage(); + await page.setContent( + html` - `, - }); - - await page.waitForChanges(); - + `, + ); + await skipAnimations(page); const actionMenu = await page.find("calcite-action-menu"); const actions = await findAll(page, "calcite-action"); const trigger = await page.find(`calcite-action-menu >>> .${CSS.defaultTrigger}`); @@ -464,9 +469,10 @@ describe("calcite-action-menu", () => { await actionMenu.callMethod("setFocus"); await page.waitForChanges(); - + const openEventSpy = await actionMenu.spyOnEvent("calciteActionMenuOpen"); await page.keyboard.press("Enter"); await page.waitForChanges(); + await openEventSpy.next(); expect(await actionMenu.getProperty("open")).toBe(true); expect(await trigger.getProperty("active")).toBe(true); @@ -475,7 +481,7 @@ describe("calcite-action-menu", () => { expect(actions[2].getAttribute(activeAttr)).toBe(null); await page.keyboard.press("ArrowDown"); - + await waitForAnimationFrame(page); await page.waitForChanges(); expect(actions[0].getAttribute(activeAttr)).toBe(null); @@ -483,7 +489,6 @@ describe("calcite-action-menu", () => { expect(actions[2].getAttribute(activeAttr)).toBe(null); await page.keyboard.press("Home"); - await page.waitForChanges(); expect(actions[0].getAttribute(activeAttr)).toBe(""); @@ -491,7 +496,6 @@ describe("calcite-action-menu", () => { expect(actions[2].getAttribute(activeAttr)).toBe(null); await page.keyboard.press("End"); - await page.waitForChanges(); expect(actions[0].getAttribute(activeAttr)).toBe(null); @@ -499,7 +503,6 @@ describe("calcite-action-menu", () => { expect(actions[2].getAttribute(activeAttr)).toBe(""); await page.keyboard.press("Escape"); - await page.waitForChanges(); expect(await actionMenu.getProperty("open")).toBe(false); @@ -524,8 +527,10 @@ describe("calcite-action-menu", () => { await actionMenu.callMethod("setFocus"); await page.waitForChanges(); + const openEventSpy = await actionMenu.spyOnEvent("calciteActionMenuOpen"); await page.keyboard.press("ArrowDown"); await page.waitForChanges(); + await openEventSpy.next(); expect(await actionMenu.getProperty("open")).toBe(true); expect(actions[0].getAttribute(activeAttr)).toBe(""); @@ -534,6 +539,7 @@ describe("calcite-action-menu", () => { await page.keyboard.press("Tab"); await page.waitForChanges(); + await waitForActionMenuClose(page); expect(await actionMenu.getProperty("open")).toBe(false); }); @@ -548,7 +554,6 @@ describe("calcite-action-menu", () => { `, ); await skipAnimations(page); - await page.waitForChanges(); const actionMenu = await page.find("calcite-action-menu"); const actions = await findAll(page, "calcite-action"); @@ -556,8 +561,10 @@ describe("calcite-action-menu", () => { await actionMenu.callMethod("setFocus"); await page.waitForChanges(); + const openEventSpy = await actionMenu.spyOnEvent("calciteActionMenuOpen"); await page.keyboard.press("ArrowDown"); await page.waitForChanges(); + await openEventSpy.next(); const clickSpy = await actions[0].spyOnEvent("click"); @@ -568,6 +575,7 @@ describe("calcite-action-menu", () => { await page.keyboard.press("Enter"); await page.waitForChanges(); + await waitForActionMenuClose(page); expect(await actionMenu.getProperty("open")).toBe(false); expect(clickSpy).toHaveReceivedEventTimes(1); @@ -583,7 +591,6 @@ describe("calcite-action-menu", () => { `, ); await skipAnimations(page); - await page.waitForChanges(); const actionMenu = await page.find("calcite-action-menu"); const actions = await findAll(page, "calcite-action"); @@ -591,8 +598,10 @@ describe("calcite-action-menu", () => { await actionMenu.callMethod("setFocus"); await page.waitForChanges(); + const openEventSpy = await actionMenu.spyOnEvent("calciteActionMenuOpen"); await page.keyboard.press("ArrowDown"); await page.waitForChanges(); + await openEventSpy.next(); const clickSpy = await actions[0].spyOnEvent("click"); @@ -606,6 +615,7 @@ describe("calcite-action-menu", () => { el.click(), ); await page.waitForChanges(); + await waitForActionMenuClose(page); expect(await actionMenu.getProperty("open")).toBe(false); expect(clickSpy).toHaveReceivedEventTimes(1); diff --git a/packages/calcite-components/src/components/block-group/block-group.e2e.ts b/packages/calcite-components/src/components/block-group/block-group.e2e.ts index d05929fae5e..1eb5b19f9fb 100755 --- a/packages/calcite-components/src/components/block-group/block-group.e2e.ts +++ b/packages/calcite-components/src/components/block-group/block-group.e2e.ts @@ -461,7 +461,7 @@ describe("calcite-block-group", () => { ): Promise { const component = await page.find("calcite-block-group"); const eventName = `calciteSortHandleReorder`; - const event = component.waitForEvent(eventName); + const eventSpy = await component.spyOnEvent(eventName); await page.$eval( `calcite-block[heading="one"]`, (item1: Block["el"], reorder, eventName) => { @@ -470,8 +470,8 @@ describe("calcite-block-group", () => { reorder, eventName, ); - await event; await page.waitForChanges(); + await eventSpy.next(); const itemsAfter = await findAll(page, "calcite-block"); expect(itemsAfter.length).toBe(3); @@ -571,6 +571,7 @@ describe("calcite-block-group", () => { ): Promise { const component = await page.find(`#${componentItemId}`); const eventName = `calciteSortHandleMove`; + // eslint-disable-next-line no-restricted-properties -- workaround for spyOnEvent throwing errors due to circular JSON structures when serializing the event payload const event = component.waitForEvent(eventName); await page.$eval( `#${componentItemId}`, diff --git a/packages/calcite-components/src/components/block/block.e2e.ts b/packages/calcite-components/src/components/block/block.e2e.ts index dbdddff5bc5..a968f63a933 100644 --- a/packages/calcite-components/src/components/block/block.e2e.ts +++ b/packages/calcite-components/src/components/block/block.e2e.ts @@ -253,7 +253,9 @@ describe("calcite-block", () => { expect(toggle.getAttribute("aria-expanded")).toBe("false"); expect(toggle.getAttribute("title")).toBe(messages.expand); + const openEventSpy = await element.spyOnEvent("calciteBlockOpen"); await toggle.click(); + await openEventSpy.next(); expect(toggleSpy).toHaveReceivedEventTimes(1); expect(openSpy).toHaveReceivedEventTimes(1); @@ -261,7 +263,9 @@ describe("calcite-block", () => { expect(toggle.getAttribute("aria-expanded")).toBe("true"); expect(toggle.getAttribute("title")).toBe(messages.collapse); + const closeEventSpy = await element.spyOnEvent("calciteBlockClose"); await toggle.click(); + await closeEventSpy.next(); expect(toggleSpy).toHaveReceivedEventTimes(2); expect(closeSpy).toHaveReceivedEventTimes(1); @@ -336,12 +340,18 @@ describe("calcite-block", () => { await control.press("Space"); await control.press("Enter"); await control.click(); + expect(blockOpenSpy).toHaveReceivedEventTimes(0); expect(blockToggleSpy).toHaveReceivedEventTimes(0); expect(blockCloseSpy).toHaveReceivedEventTimes(0); + const openEventSpy = await page.spyOnEvent("calciteBlockOpen"); + const closeEventSpy = await page.spyOnEvent("calciteBlockClose"); await block.click(); + await openEventSpy.next(); await block.click(); + await closeEventSpy.next(); + expect(blockToggleSpy).toHaveReceivedEventTimes(2); expect(blockOpenSpy).toHaveReceivedEventTimes(1); expect(blockCloseSpy).toHaveReceivedEventTimes(1); diff --git a/packages/calcite-components/src/components/button/button.e2e.ts b/packages/calcite-components/src/components/button/button.e2e.ts index 925732807f3..7281b9b90f4 100644 --- a/packages/calcite-components/src/components/button/button.e2e.ts +++ b/packages/calcite-components/src/components/button/button.e2e.ts @@ -497,77 +497,6 @@ describe("calcite-button", () => { expect(elementAsButton).not.toHaveClass(CSS.contentSlotted); }); - describe("CSS properties for light/dark mode", () => { - const buttonSnippet = ` - - Layers - - `; - - it("should have defined CSS custom properties", async () => { - const page = await newE2EPage({ html: buttonSnippet }); - const buttonStyles = await page.evaluate(() => { - const buttonEl = document.querySelector("calcite-button"); - buttonEl.style.setProperty("--calcite-color-transparent-hover", "rgba(34, 23, 200, 0.4)"); - buttonEl.style.setProperty("--calcite-color-transparent-press", "rgba(1, 20, 44, 0.1"); - return { - hoverFocus: window.getComputedStyle(buttonEl).getPropertyValue("--calcite-color-transparent-hover"), - active: window.getComputedStyle(buttonEl).getPropertyValue("--calcite-color-transparent-press"), - }; - }); - expect(buttonStyles.hoverFocus).toEqual("rgba(34, 23, 200, 0.4)"); - expect(buttonStyles.active).toEqual("rgba(1, 20, 44, 0.1"); - }); - - describe("when mode attribute is not provided", () => { - it("should render button pseudo classes with default values tied to light mode", async () => { - const page = await newE2EPage({ html: buttonSnippet }); - const buttonEl = await page.find("calcite-button >>> button"); - await buttonEl.hover(); - await page.waitForChanges(); - const buttonHoverStyle = await buttonEl.getComputedStyle(); - expect(buttonHoverStyle.getPropertyValue("background-color")).toEqual("rgba(0, 0, 0, 0.04)"); - }); - }); - - describe("when mode attribute is dark", () => { - it("should render button pseudo classes with value tied to dark mode", async () => { - const page = await newE2EPage({ - html: `
${buttonSnippet}
`, - }); - const buttonEl = await page.find("calcite-button >>> button"); - await buttonEl.hover(); - await page.waitForChanges(); - const buttonHoverStyle = await buttonEl.getComputedStyle(); - expect(buttonHoverStyle.getPropertyValue("background-color")).toEqual("rgba(255, 255, 255, 0.12)"); - }); - }); - - it("should allow the CSS custom property to be overridden", async () => { - const overrideStyle = "rgba(255, 255, 0, 0.9)"; - const page = await newE2EPage({ - html: ` - -
${buttonSnippet}
`, - }); - const buttonEl = await page.find("calcite-button >>> button"); - await buttonEl.hover(); - await page.waitForChanges(); - const buttonHoverStyle = await buttonEl.getComputedStyle(); - expect(buttonHoverStyle.getPropertyValue("background-color")).toEqual(overrideStyle); - }); - }); - it("should remove calcite-loader from dom when `loading` is false", async () => { const page = await newE2EPage(); await page.setContent(``); diff --git a/packages/calcite-components/src/components/card-group/card-group.e2e.ts b/packages/calcite-components/src/components/card-group/card-group.e2e.ts index e858554b136..27e1e900f90 100644 --- a/packages/calcite-components/src/components/card-group/card-group.e2e.ts +++ b/packages/calcite-components/src/components/card-group/card-group.e2e.ts @@ -90,8 +90,10 @@ describe("calcite-card-group", () => { expect(await element.getProperty("selectedItems")).toHaveLength(1); await selectedItemAsserter([card2.id]); - card1CheckAction.click(); - await page.waitForChanges(); + const selectEventSpy = await page.spyOnEvent("calciteCardSelect"); + await card1CheckAction.click(); + await selectEventSpy.next(); + expect(await cardGroupSelectSpy).toHaveReceivedEventTimes(1); expect(await cardSelectSpy1).toHaveReceivedEventTimes(1); expect(await cardSelectSpy2).toHaveReceivedEventTimes(0); @@ -100,8 +102,9 @@ describe("calcite-card-group", () => { expect(await element.getProperty("selectedItems")).toHaveLength(1); await selectedItemAsserter([card1.id]); - card2CheckAction.click(); - await page.waitForChanges(); + await card2CheckAction.click(); + await selectEventSpy.next(); + expect(cardGroupSelectSpy).toHaveReceivedEventTimes(2); expect(cardSelectSpy1).toHaveReceivedEventTimes(1); expect(cardSelectSpy2).toHaveReceivedEventTimes(1); @@ -110,8 +113,9 @@ describe("calcite-card-group", () => { expect(await element.getProperty("selectedItems")).toHaveLength(1); await selectedItemAsserter([card2.id]); - card2CheckAction.click(); - await page.waitForChanges(); + await card2CheckAction.click(); + await selectEventSpy.next(); + expect(cardGroupSelectSpy).toHaveReceivedEventTimes(3); expect(cardSelectSpy1).toHaveReceivedEventTimes(1); expect(cardSelectSpy2).toHaveReceivedEventTimes(2); @@ -148,24 +152,28 @@ describe("calcite-card-group", () => { expect(await element.getProperty("selectedItems")).toHaveLength(1); await selectedItemAsserter([card1.id]); - card1CheckAction.click(); - await page.waitForChanges(); + const selectEventSpy = await page.spyOnEvent("calciteCardSelect"); + await card1CheckAction.click(); + await selectEventSpy.next(); + expect(cardGroupSelectSpy).toHaveReceivedEventTimes(1); expect(await card1.getProperty("selected")).toBe(true); expect(await card2.getProperty("selected")).toBe(false); expect(await element.getProperty("selectedItems")).toHaveLength(1); await selectedItemAsserter([card1.id]); - card2CheckAction.click(); - await page.waitForChanges(); + await card2CheckAction.click(); + await selectEventSpy.next(); + expect(cardGroupSelectSpy).toHaveReceivedEventTimes(2); expect(await card1.getProperty("selected")).toBe(false); expect(await card2.getProperty("selected")).toBe(true); expect(await element.getProperty("selectedItems")).toHaveLength(1); await selectedItemAsserter([card2.id]); - card2CheckAction.click(); - await page.waitForChanges(); + await card2CheckAction.click(); + await selectEventSpy.next(); + expect(cardGroupSelectSpy).toHaveReceivedEventTimes(3); expect(await card1.getProperty("selected")).toBe(false); expect(await card2.getProperty("selected")).toBe(true); @@ -203,8 +211,10 @@ describe("calcite-card-group", () => { expect(await element.getProperty("selectedItems")).toEqual([]); await selectedItemAsserter([]); - card1CheckAction.click(); - await page.waitForChanges(); + const selectEventSpy = await page.spyOnEvent("calciteCardSelect"); + await card1CheckAction.click(); + await selectEventSpy.next(); + expect(cardGroupSelectSpy).toHaveReceivedEventTimes(1); expect(await card1.getProperty("selected")).toBe(true); expect(await card2.getProperty("selected")).toBe(false); @@ -212,8 +222,9 @@ describe("calcite-card-group", () => { expect(await element.getProperty("selectedItems")).toHaveLength(1); await selectedItemAsserter([card1.id]); - card2CheckAction.click(); - await page.waitForChanges(); + await card2CheckAction.click(); + await selectEventSpy.next(); + expect(cardGroupSelectSpy).toHaveReceivedEventTimes(2); expect(await card1.getProperty("selected")).toBe(true); expect(await card2.getProperty("selected")).toBe(true); @@ -221,8 +232,9 @@ describe("calcite-card-group", () => { expect(await element.getProperty("selectedItems")).toHaveLength(2); await selectedItemAsserter([card1.id, card2.id]); - card3CheckAction.click(); - await page.waitForChanges(); + await card3CheckAction.click(); + await selectEventSpy.next(); + expect(cardGroupSelectSpy).toHaveReceivedEventTimes(3); expect(await card1.getProperty("selected")).toBe(true); expect(await card2.getProperty("selected")).toBe(true); @@ -230,8 +242,9 @@ describe("calcite-card-group", () => { expect(await element.getProperty("selectedItems")).toHaveLength(3); await selectedItemAsserter([card1.id, card2.id, card3.id]); - card1CheckAction.click(); - await page.waitForChanges(); + await card1CheckAction.click(); + await selectEventSpy.next(); + expect(cardGroupSelectSpy).toHaveReceivedEventTimes(4); expect(await card1.getProperty("selected")).toBe(false); expect(await card2.getProperty("selected")).toBe(true); @@ -239,8 +252,9 @@ describe("calcite-card-group", () => { expect(await element.getProperty("selectedItems")).toHaveLength(2); await selectedItemAsserter([card2.id, card3.id]); - card2CheckAction.click(); - await page.waitForChanges(); + await card2CheckAction.click(); + await selectEventSpy.next(); + expect(cardGroupSelectSpy).toHaveReceivedEventTimes(5); expect(await card1.getProperty("selected")).toBe(false); expect(await card2.getProperty("selected")).toBe(false); @@ -248,8 +262,9 @@ describe("calcite-card-group", () => { expect(await element.getProperty("selectedItems")).toHaveLength(1); await selectedItemAsserter([card3.id]); - card3CheckAction.click(); - await page.waitForChanges(); + await card3CheckAction.click(); + await selectEventSpy.next(); + expect(cardGroupSelectSpy).toHaveReceivedEventTimes(6); expect(await card1.getProperty("selected")).toBe(false); expect(await card2.getProperty("selected")).toBe(false); diff --git a/packages/calcite-components/src/components/carousel/carousel.e2e.ts b/packages/calcite-components/src/components/carousel/carousel.e2e.ts index e7a54e40ed6..7ce803ec35b 100644 --- a/packages/calcite-components/src/components/carousel/carousel.e2e.ts +++ b/packages/calcite-components/src/components/carousel/carousel.e2e.ts @@ -1037,52 +1037,66 @@ describe("calcite-carousel", () => { it("item slide animation finishes between paging/selection", async () => { const page = await newE2EPage(); await page.setContent( - html` -

first

-

second

-

third

-
`, + html` + +

first

+

second

+

third

+
`, ); const container = await page.find(`calcite-carousel >>> .${CSS.container}`); - const animationStartSpy = await container.spyOnEvent("animationstart"); - const animationEndSpy = await container.spyOnEvent("animationend"); + const animationStartEventSpy = await container.spyOnEvent("animationstart"); + const animationEndEventSpy = await container.spyOnEvent("animationend"); const nextButton = await page.find(`calcite-carousel >>> .${CSS.pageNext}`); await nextButton.click(); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); await nextButton.click(); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); - expect(animationStartSpy).toHaveReceivedEventTimes(2); - expect(animationEndSpy).toHaveReceivedEventTimes(2); + expect(animationStartEventSpy).toHaveReceivedEventTimes(2); + expect(animationEndEventSpy).toHaveReceivedEventTimes(2); const previousButton = await page.find(`calcite-carousel >>> .${CSS.pagePrevious}`); await previousButton.click(); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); await previousButton.click(); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); - expect(animationStartSpy).toHaveReceivedEventTimes(4); - expect(animationEndSpy).toHaveReceivedEventTimes(4); + expect(animationStartEventSpy).toHaveReceivedEventTimes(4); + expect(animationEndEventSpy).toHaveReceivedEventTimes(4); const [item1, item2, item3] = await findAll(page, `calcite-carousel >>> .${CSS.paginationItemIndividual}`); await item2.click(); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); await item3.click(); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); - expect(animationStartSpy).toHaveReceivedEventTimes(6); - expect(animationEndSpy).toHaveReceivedEventTimes(6); + expect(animationStartEventSpy).toHaveReceivedEventTimes(6); + expect(animationEndEventSpy).toHaveReceivedEventTimes(6); await item2.click(); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); await item1.click(); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); - expect(animationStartSpy).toHaveReceivedEventTimes(8); - expect(animationEndSpy).toHaveReceivedEventTimes(8); + expect(animationStartEventSpy).toHaveReceivedEventTimes(8); + expect(animationEndEventSpy).toHaveReceivedEventTimes(8); }); it("item slide animation finishes between paging/selection with autoplay", async () => { @@ -1096,53 +1110,47 @@ describe("calcite-carousel", () => { ); const container = await page.find(`calcite-carousel >>> .${CSS.container}`); - const animationStartSpy = await container.spyOnEvent("animationstart"); - const animationEndSpy = await container.spyOnEvent("animationend"); + const animationStartEventSpy = await container.spyOnEvent("animationstart"); + const animationEndEventSpy = await container.spyOnEvent("animationend"); const nextButton = await page.find(`calcite-carousel >>> .${CSS.pageNext}`); await nextButton.click(); - await page.waitForTimeout(customDuration); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); - expect(animationStartSpy).toHaveReceivedEventTimes(1); - expect(animationEndSpy).toHaveReceivedEventTimes(1); + expect(animationStartEventSpy).toHaveReceivedEventTimes(1); + expect(animationEndEventSpy).toHaveReceivedEventTimes(1); const previousButton = await page.find(`calcite-carousel >>> .${CSS.pagePrevious}`); await previousButton.click(); - await page.waitForTimeout(customDuration); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); - expect(animationStartSpy).toHaveReceivedEventTimes(2); - expect(animationEndSpy).toHaveReceivedEventTimes(2); + expect(animationStartEventSpy).toHaveReceivedEventTimes(2); + expect(animationEndEventSpy).toHaveReceivedEventTimes(2); const [item1, item2, item3] = await findAll(page, `calcite-carousel >>> .${CSS.paginationItemIndividual}`); await item2.click(); - await page.waitForTimeout(customDuration); - await page.waitForChanges(); - await page.waitForTimeout(customDuration); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); - expect(animationStartSpy).toHaveReceivedEventTimes(3); - expect(animationEndSpy).toHaveReceivedEventTimes(3); + expect(animationStartEventSpy).toHaveReceivedEventTimes(3); + expect(animationEndEventSpy).toHaveReceivedEventTimes(3); await item3.click(); - await page.waitForTimeout(customDuration); - await page.waitForChanges(); - await page.waitForTimeout(customDuration); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); - expect(animationStartSpy).toHaveReceivedEventTimes(4); - expect(animationEndSpy).toHaveReceivedEventTimes(4); + expect(animationStartEventSpy).toHaveReceivedEventTimes(4); + expect(animationEndEventSpy).toHaveReceivedEventTimes(4); await item1.click(); - await page.waitForTimeout(customDuration); - await page.waitForChanges(); - await page.waitForTimeout(customDuration); - await page.waitForChanges(); + await animationStartEventSpy.next(); + await animationEndEventSpy.next(); - expect(animationStartSpy).toHaveReceivedEventTimes(5); - expect(animationEndSpy).toHaveReceivedEventTimes(5); + expect(animationStartEventSpy).toHaveReceivedEventTimes(5); + expect(animationEndEventSpy).toHaveReceivedEventTimes(5); }); }); diff --git a/packages/calcite-components/src/components/chip/chip.e2e.ts b/packages/calcite-components/src/components/chip/chip.e2e.ts index 53f5ea89630..a9be591a83d 100644 --- a/packages/calcite-components/src/components/chip/chip.e2e.ts +++ b/packages/calcite-components/src/components/chip/chip.e2e.ts @@ -163,90 +163,17 @@ describe("calcite-chip", () => { }); }); - describe("CSS properties for light/dark mode", () => { - const chipSnippet = ` - - Layers - - `; - let page; - let chipCloseButton; - let chipCloseButtonFocusStyle; - let chipCloseButtonHoverStyle; - - describe("when mode attribute is not provided", () => { - it("should render chip pseudo classes with default values tied to mode", async () => { - page = await newE2EPage({ html: chipSnippet }); - chipCloseButton = await page.find("calcite-chip >>> button"); - await chipCloseButton.focus(); - await page.waitForChanges(); - chipCloseButtonFocusStyle = await chipCloseButton.getComputedStyle(); - expect(chipCloseButtonFocusStyle.getPropertyValue("background-color")).toEqual("rgba(0, 0, 0, 0.04)"); - - await chipCloseButton.hover(); - await page.waitForChanges(); - chipCloseButtonHoverStyle = await chipCloseButton.getComputedStyle(); - expect(chipCloseButtonHoverStyle.getPropertyValue("background-color")).toEqual("rgba(0, 0, 0, 0.04)"); - }); - }); - - describe("when mode attribute is dark", () => { - it("should render button pseudo classes with value tied to dark mode", async () => { - page = await newE2EPage({ - html: `
${chipSnippet}
`, - }); - chipCloseButton = await page.find("calcite-chip >>> button"); - await chipCloseButton.focus(); - await page.waitForChanges(); - chipCloseButtonFocusStyle = await chipCloseButton.getComputedStyle(); - expect(chipCloseButtonFocusStyle.getPropertyValue("background-color")).toEqual("rgba(255, 255, 255, 0.12)"); - - await chipCloseButton.hover(); - await page.waitForChanges(); - chipCloseButtonHoverStyle = await chipCloseButton.getComputedStyle(); - expect(chipCloseButtonHoverStyle.getPropertyValue("background-color")).toEqual("rgba(255, 255, 255, 0.12)"); - }); - }); - - it("should allow the CSS custom property to be overridden", async () => { - const overrideStyle = "rgba(55, 5, 10, 0.19)"; - page = await newE2EPage({ - html: ` - -
${chipSnippet}
`, - }); - chipCloseButton = await page.find("calcite-chip >>> button"); - await chipCloseButton.focus(); - await page.waitForChanges(); - chipCloseButtonFocusStyle = await chipCloseButton.getComputedStyle(); - expect(chipCloseButtonFocusStyle.getPropertyValue("background-color")).toEqual(overrideStyle); - - await chipCloseButton.hover(); - await page.waitForChanges(); - chipCloseButtonHoverStyle = await chipCloseButton.getComputedStyle(); - expect(chipCloseButtonHoverStyle.getPropertyValue("background-color")).toEqual(overrideStyle); - }); - - it("should not render chip when closed set to true", async () => { - const page = await newE2EPage(); - await page.setContent(`
${chipSnippet}
`); + it("should not render chip when closed set to true", async () => { + const page = await newE2EPage(); + await page.setContent(html` + Layers + `); - const chipEl = await page.find(`calcite-chip`); - chipEl.toggleAttribute("closed", true); - await page.waitForChanges(); + const chipEl = await page.find(`calcite-chip`); + chipEl.toggleAttribute("closed", true); + await page.waitForChanges(); - expect(await chipEl.isVisible()).toBe(false); - }); + expect(await chipEl.isVisible()).toBe(false); }); describe("translation support", () => { diff --git a/packages/calcite-components/src/components/color-picker/color-picker.e2e.ts b/packages/calcite-components/src/components/color-picker/color-picker.e2e.ts index 04957f1915e..6c1d3351693 100644 --- a/packages/calcite-components/src/components/color-picker/color-picker.e2e.ts +++ b/packages/calcite-components/src/components/color-picker/color-picker.e2e.ts @@ -2408,58 +2408,6 @@ describe("calcite-color-picker", () => { }); }); - describe("mouse", () => { - const moveByInPx = 2; - - it("should update value when color field scope is moved", async () => { - const page = await newE2EPage(); - await page.setContent(html``); - const colorPicker = await page.find("calcite-color-picker"); - - const [colorFieldScopeX, colorFieldScopeY] = await getElementXY( - page, - "calcite-color-picker", - `.${CSS.colorFieldScope}`, - ); - const value = await colorPicker.getProperty("value"); - - await page.mouse.click(colorFieldScopeX - moveByInPx, colorFieldScopeY); - await page.waitForChanges(); - expect(await colorPicker.getProperty("value")).not.toBe(value); - }); - - it("should update value when hue scope is moved", async () => { - const page = await newE2EPage(); - await page.setContent(html``); - const colorPicker = await page.find("calcite-color-picker"); - - const [hueScopeX, hueScopeY] = await getElementXY(page, "calcite-color-picker", `.${CSS.hueScope}`); - const value = await colorPicker.getProperty("value"); - - await page.mouse.click(hueScopeX - moveByInPx, hueScopeY); - await page.waitForChanges(); - expect(await colorPicker.getProperty("value")).not.toBe(value); - }); - - it("should update value when opacity scope is moved", async () => { - const page = await newE2EPage(); - await page.setContent( - html``, - ); - const [opacityScopeX, opacityScopeY] = await getElementXY( - page, - "calcite-color-picker", - `.${CSS.opacityScope}`, - ); - const colorPicker = await page.find("calcite-color-picker"); - const value = await colorPicker.getProperty("value"); - - await page.mouse.click(opacityScopeX - moveByInPx, opacityScopeY); - await page.waitForChanges(); - expect(await colorPicker.getProperty("value")).not.toBe(value); - }); - }); - describe("alpha channel", () => { it("allows editing alpha value via keyboard", async () => { const page = await newE2EPage(); @@ -2486,6 +2434,54 @@ describe("calcite-color-picker", () => { }); }); }); + + describe("mouse", () => { + const moveByInPx = 2; + + it("should update value when color field scope is moved", async () => { + const page = await newE2EPage(); + await page.setContent(html` `); + const colorPicker = await page.find("calcite-color-picker"); + + const [colorFieldScopeX, colorFieldScopeY] = await getElementXY( + page, + "calcite-color-picker", + `.${CSS.colorFieldScope}`, + ); + const value = await colorPicker.getProperty("value"); + + await page.mouse.click(colorFieldScopeX - moveByInPx, colorFieldScopeY); + await page.waitForChanges(); + expect(await colorPicker.getProperty("value")).not.toBe(value); + }); + + it("should update value when hue scope is moved", async () => { + const page = await newE2EPage(); + await page.setContent(html` `); + const colorPicker = await page.find("calcite-color-picker"); + + const [hueScopeX, hueScopeY] = await getElementXY(page, "calcite-color-picker", `.${CSS.hueScope}`); + const value = await colorPicker.getProperty("value"); + + await page.mouse.click(hueScopeX - moveByInPx, hueScopeY); + await page.waitForChanges(); + expect(await colorPicker.getProperty("value")).not.toBe(value); + }); + + it("should update value when opacity scope is moved", async () => { + const page = await newE2EPage(); + await page.setContent( + html` `, + ); + const [opacityScopeX, opacityScopeY] = await getElementXY(page, "calcite-color-picker", `.${CSS.opacityScope}`); + const colorPicker = await page.find("calcite-color-picker"); + const value = await colorPicker.getProperty("value"); + + await page.mouse.click(opacityScopeX - moveByInPx, opacityScopeY); + await page.waitForChanges(); + expect(await colorPicker.getProperty("value")).not.toBe(value); + }); + }); }); it("does not throw when initialized with different format value (format='auto')", async () => { diff --git a/packages/calcite-components/src/components/combobox/combobox.e2e.ts b/packages/calcite-components/src/components/combobox/combobox.e2e.ts index 3e23e97660e..21609f8e39f 100644 --- a/packages/calcite-components/src/components/combobox/combobox.e2e.ts +++ b/packages/calcite-components/src/components/combobox/combobox.e2e.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { E2EElement, E2EPage, newE2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; +import { E2EElement, E2EPage, EventSpy, newE2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; import { beforeEach, describe, expect, it } from "vitest"; import { accessible, @@ -297,10 +297,9 @@ describe("calcite-combobox", () => { await combobox.press("Escape"); // closes list await combobox.press("Escape"); // clears input - const filterEvent = combobox.waitForEvent("calciteComboboxFilterChange"); + const filterEventSpy = await combobox.spyOnEvent("calciteComboboxFilterChange"); await combobox.type(text); - await filterEvent; - await page.waitForChanges(); + await filterEventSpy.next(); } }); @@ -1003,9 +1002,9 @@ describe("calcite-combobox", () => { `); const element = await page.find("calcite-combobox"); - const openEvent = page.waitForEvent("calciteComboboxOpen"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await element.click(); - await openEvent; + await openEventSpy.next(); await element.press("p"); await element.press("i"); @@ -1044,18 +1043,17 @@ describe("calcite-combobox", () => { `); const combobox = await page.find("calcite-combobox"); - const firstOpenEvent = page.waitForEvent("calciteComboboxOpen"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await combobox.click(); - await firstOpenEvent; + await openEventSpy.next(); const item1 = await combobox.find("calcite-combobox-item[value=one]"); await selectItem(item1); expect(await combobox.getProperty("value")).toBe("one"); - const secondOpenEvent = page.waitForEvent("calciteComboboxOpen"); await combobox.click(); - await secondOpenEvent; + await openEventSpy.next(); await selectItem(item1); expect(await combobox.getProperty("value")).toBe(""); @@ -1070,18 +1068,17 @@ describe("calcite-combobox", () => { `); const combobox = await page.find("calcite-combobox"); - const firstOpenEvent = page.waitForEvent("calciteComboboxOpen"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await combobox.click(); - await firstOpenEvent; + await openEventSpy.next(); const item1 = await combobox.find("calcite-combobox-item[value=one]"); await selectItem(item1); expect(await combobox.getProperty("value")).toBe("one"); - const secondOpenEvent = page.waitForEvent("calciteComboboxOpen"); await combobox.click(); - await secondOpenEvent; + await openEventSpy.next(); await selectItem(item1); expect(await combobox.getProperty("value")).toBe("one"); @@ -1099,9 +1096,9 @@ describe("calcite-combobox", () => { const combobox = await page.find("calcite-combobox"); - const firstOpenEvent = page.waitForEvent("calciteComboboxOpen"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await combobox.click(); - await firstOpenEvent; + await openEventSpy.next(); const item1 = await combobox.find("calcite-combobox-item[heading=one]"); const item2 = await combobox.find("calcite-combobox-item[heading=two]"); @@ -1113,9 +1110,8 @@ describe("calcite-combobox", () => { expect(await item2.getProperty("selected")).toBe(false); expect(await combobox.getProperty("open")).toBe(false); - const secondOpenEvent = page.waitForEvent("calciteComboboxOpen"); await combobox.click(); - await secondOpenEvent; + await openEventSpy.next(); await item2.click(); await page.waitForChanges(); @@ -1134,9 +1130,9 @@ describe("calcite-combobox", () => { `); const combobox = await page.find("calcite-combobox"); - const openEvent = page.waitForEvent("calciteComboboxOpen"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await combobox.click(); - await openEvent; + await openEventSpy.next(); const item1 = await combobox.find("calcite-combobox-item[value=one]"); @@ -1161,9 +1157,9 @@ describe("calcite-combobox", () => { `); const combobox = await page.find("calcite-combobox"); - const openEvent = page.waitForEvent("calciteComboboxOpen"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await combobox.click(); - await openEvent; + await openEventSpy.next(); const item1 = await combobox.find("calcite-combobox-item[value=one]"); @@ -1189,9 +1185,9 @@ describe("calcite-combobox", () => { `); const combobox = await page.find("calcite-combobox"); - const openEvent = page.waitForEvent("calciteComboboxOpen"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await combobox.click(); - await openEvent; + await openEventSpy.next(); const item1 = await combobox.find("calcite-combobox-item[value=child1]"); await item1.click(); @@ -1215,9 +1211,9 @@ describe("calcite-combobox", () => { `); const combobox = await page.find("calcite-combobox"); - const openEvent = page.waitForEvent("calciteComboboxOpen"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await combobox.click(); - await openEvent; + await openEventSpy.next(); const parent = await combobox.find("calcite-combobox-item[value=parent]"); const parentItem = await combobox.find("calcite-combobox-item[value=parent] >>> li"); @@ -1246,9 +1242,9 @@ describe("calcite-combobox", () => { `); const combobox = await page.find("calcite-combobox"); - const openEvent = page.waitForEvent("calciteComboboxOpen"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await combobox.click(); - await openEvent; + await openEventSpy.next(); const item1 = await combobox.find("calcite-combobox-item[value=one]"); await item1.click(); @@ -1272,20 +1268,17 @@ describe("calcite-combobox", () => { it("should honor calciteComboboxChipClose", async () => { const page = await newE2EPage(); - await page.setContent( html` `, ); - const eventSpy = await page.spyOnEvent("calciteComboboxChipClose"); - const chip = await page.find("calcite-combobox >>> calcite-chip"); chip.triggerEvent("calciteChipClose"); - await page.waitForChanges(); + await eventSpy.next(); expect(eventSpy).toHaveReceivedEventTimes(1); }); @@ -1574,8 +1567,10 @@ describe("calcite-combobox", () => { expect(await getDataTestId()).toBe(inputId); await assertCaretPosition({ page, componentTag, position: 0 }); + const filterChangeEventSpy = await page.spyOnEvent("calciteComboboxFilterChange"); await page.keyboard.type("zz"); await page.waitForChanges(); + await filterChangeEventSpy.next(); await page.keyboard.press("ArrowRight"); await page.waitForChanges(); @@ -1668,6 +1663,7 @@ describe("calcite-combobox", () => { `); + await skipAnimations(page); }); it("should not show the listbox when it receives focus", async () => { @@ -1690,19 +1686,22 @@ describe("calcite-combobox", () => { }); it("tab will close the item group if it’s open", async () => { - await skipAnimations(page); const inputEl = await page.find(`#myCombobox >>> input`); await inputEl.focus(); await page.waitForChanges(); expect(await page.evaluate(() => document.activeElement.id)).toBe("myCombobox"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await page.keyboard.press("Space"); await page.waitForChanges(); + await openEventSpy.next(); const floatingUI = await page.find(`#myCombobox >>> .${CSS.floatingUIContainer}`); expect(await floatingUI.isVisible()).toBe(true); + const closeEventSpy = await page.spyOnEvent("calciteComboboxClose"); await page.keyboard.press("Tab"); await page.waitForChanges(); + await closeEventSpy.next(); expect(await floatingUI.isVisible()).toBe(false); }); @@ -1728,30 +1727,39 @@ describe("calcite-combobox", () => { const inputEl = await page.find(`#myCombobox >>> input`); await inputEl.focus(); await page.waitForChanges(); + expect(await page.evaluate(() => document.activeElement.id)).toBe("myCombobox"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await page.keyboard.press("ArrowDown"); await page.waitForChanges(); + await openEventSpy.next(); const firstFocusedGroupItem = await page.find(`#one >>> .${ComboboxItemCSS.active}`); + expect(firstFocusedGroupItem).toBeTruthy(); }); it(`Escape closes the dropdown, but remains focused`, async () => { - await skipAnimations(page); const inputEl = await page.find(`#myCombobox >>> input`); await inputEl.focus(); await page.waitForChanges(); + expect(await page.evaluate(() => document.activeElement.id)).toBe("myCombobox"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await page.keyboard.press("Space"); await page.waitForChanges(); + await openEventSpy.next(); const floatingUI = await page.find(`#myCombobox >>> .${CSS.floatingUIContainer}`); + expect(await floatingUI.isVisible()).toBe(true); + const closeEventSpy = await page.spyOnEvent("calciteComboboxClose"); await page.keyboard.press("Escape"); await page.waitForChanges(); - expect(await floatingUI.isVisible()).toBe(false); + await closeEventSpy.next(); + expect(await floatingUI.isVisible()).toBe(false); expect(await page.evaluate(() => document.activeElement.id)).toBe("myCombobox"); }); @@ -1759,15 +1767,18 @@ describe("calcite-combobox", () => { const inputEl = await page.find(`#myCombobox >>> input`); await inputEl.focus(); await page.waitForChanges(); + expect(await page.evaluate(() => document.activeElement.id)).toBe("myCombobox"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await page.keyboard.press("Space"); await page.waitForChanges(); + await openEventSpy.next(); const firstFocusedGroupItem = await page.find(`#one >>> .${ComboboxItemCSS.active}`); + expect(firstFocusedGroupItem).toBeTruthy(); - const visible = await firstFocusedGroupItem.isVisible(); - expect(visible).toBe(true); + expect(await firstFocusedGroupItem.isVisible()).toBe(true); await page.keyboard.press("Space"); await page.waitForChanges(); @@ -1995,9 +2006,8 @@ describe("calcite-combobox", () => { const eventSpy = await page.spyOnEvent("calciteComboboxChange"); const two = await page.find("#two"); - const event = page.waitForEvent("calciteComboboxChange"); await two.click(); - await event; + await eventSpy.next(); const combobox = await page.find("calcite-combobox"); @@ -2022,9 +2032,8 @@ describe("calcite-combobox", () => { const eventSpy = await page.spyOnEvent("calciteComboboxChange"); const two = await page.find("#two"); - const event = page.waitForEvent("calciteComboboxChange"); await two.click(); - await event; + await eventSpy.next(); expect(eventSpy).toHaveReceivedEventTimes(1); expect((await element.getProperty("selectedItems")).length).toBe(2); @@ -2057,7 +2066,7 @@ describe("calcite-combobox", () => { let element: E2EElement; let comboboxItem: E2EElement; let itemNestedLi: E2EElement; - let closeEvent: Promise; + let closeEventSpy: EventSpy; beforeEach(async () => { page = await newE2EPage(); @@ -2085,14 +2094,14 @@ describe("calcite-combobox", () => { await page.waitForChanges(); itemNestedLi = await page.find("calcite-combobox-item#PineNested >>> li"); - closeEvent = page.waitForEvent("calciteComboboxClose"); + closeEventSpy = await page.spyOnEvent("calciteComboboxClose"); }); it("clicking on Listbox item focuses on the item and closes out of Listbox with tab", async () => { expect(itemNestedLi).toHaveClass(ComboboxItemCSS.active); await element.press("Tab"); - await closeEvent; + await closeEventSpy.next(); await element.press("Tab"); expect(await page.evaluate(() => document.activeElement.id)).not.toBe("calcite-combobox"); }); @@ -2112,7 +2121,7 @@ describe("calcite-combobox", () => { expect(itemNestedLi).toHaveClass(ComboboxItemCSS.active); await element.press("Tab"); - await closeEvent; + await closeEventSpy.next(); await element.press("Tab"); expect(await page.evaluate(() => document.activeElement.id)).not.toBe("calcite-combobox"); }); @@ -2298,9 +2307,9 @@ describe("calcite-combobox", () => { expect(items.length).toBe(3); const item1 = await page.find("calcite-combobox-item[value=one]"); - const closeEvent = page.waitForEvent("calciteComboboxClose"); + const closeEventSpy = await page.spyOnEvent("calciteComboboxClose"); await item1.click(); - await closeEvent; + await closeEventSpy.next(); const label = await page.find("calcite-combobox >>> .label"); await page.waitForChanges(); const labelVisible = await label.isVisible(); @@ -2326,9 +2335,9 @@ describe("calcite-combobox", () => { expect(chip).toBeNull(); const combobox = await page.find("calcite-combobox"); - const openEvent = page.waitForEvent("calciteComboboxOpen"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await combobox.click(); - await openEvent; + await openEventSpy.next(); const items = await findAll(page, "calcite-combobox-item"); await items[0].click(); @@ -2548,9 +2557,9 @@ describe("calcite-combobox", () => { const page = await newE2EPage(); await page.setContent(html); await skipAnimations(page); - const openEvent = page.waitForEvent("calciteComboboxOpen"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await page.click("calcite-combobox"); - await openEvent; + await openEventSpy.next(); const activeItem = await page.find("calcite-combobox-item[active]"); expect(await activeItem.getProperty("value")).toBe(expectedActiveItemValue); @@ -2843,9 +2852,9 @@ describe("calcite-combobox", () => { `); const combobox = await page.find("calcite-combobox"); - const openEvent = page.waitForEvent("calciteComboboxOpen"); + const openEventSpy = await page.spyOnEvent("calciteComboboxOpen"); await combobox.click(); - await openEvent; + await openEventSpy.next(); await (await combobox.find("calcite-combobox-item[value=Pikachu]")).click(); await (await combobox.find("calcite-combobox-item[value=Charizard]")).click(); @@ -2854,9 +2863,9 @@ describe("calcite-combobox", () => { const chips = await findAll(page, "calcite-combobox >>> calcite-chip"); expect(chips.length).toBe(3); - const closeEvent = page.waitForEvent("calciteComboboxClose"); + const closeEventSpy = await page.spyOnEvent("calciteComboboxClose"); await combobox.press("Tab"); - await closeEvent; + await closeEventSpy.next(); const close = await page.find("calcite-combobox >>> calcite-chip >>> .close"); await close.press(" "); diff --git a/packages/calcite-components/src/components/dialog/dialog.e2e.ts b/packages/calcite-components/src/components/dialog/dialog.e2e.ts index a16c2912d7d..3d12c48e6ce 100644 --- a/packages/calcite-components/src/components/dialog/dialog.e2e.ts +++ b/packages/calcite-components/src/components/dialog/dialog.e2e.ts @@ -241,7 +241,7 @@ describe("calcite-dialog", () => { accessible(async () => { const page = await newProgrammaticE2EPage(); await skipAnimations(page); - const openEvent = page.waitForEvent("calciteDialogOpen"); + const openEventSpy = await page.spyOnEvent("calciteDialogOpen"); await page.evaluate(() => { const dialog = document.createElement("calcite-dialog"); dialog.open = true; @@ -249,7 +249,7 @@ describe("calcite-dialog", () => { dialog.description = "My Description"; document.body.append(dialog); }); - await openEvent; + await openEventSpy.next(); return { page, tag: "calcite-dialog" }; }); @@ -487,12 +487,17 @@ describe("calcite-dialog", () => { await page.$eval("calcite-dialog", (el: Dialog["el"]) => (el.beforeClose = (window as TestWindow).beforeClose)); await page.waitForChanges(); + const openEventSpy = await page.spyOnEvent("calciteDialogOpen"); dialog.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); + expect(await page.find(`calcite-dialog >>> .${CSS.containerOpen}`)).toBeDefined(); + const closeEventSpy = await page.spyOnEvent("calciteDialogClose"); await page.keyboard.press("Escape"); await page.waitForChanges(); + await closeEventSpy; expect(mockCallBack).toHaveBeenCalledTimes(2); expect(await page.find(`calcite-dialog >>> .${CSS.containerOpen}`)).toBeNull(); @@ -584,10 +589,10 @@ describe("calcite-dialog", () => { `, ); const dialog = await page.find("calcite-dialog"); - const opened = page.waitForEvent("calciteDialogOpen"); + const openEventSpy = await page.spyOnEvent("calciteDialogOpen"); dialog.setProperty("open", true); await page.waitForChanges(); - await opened; + await openEventSpy.next(); expect(await isElementFocused(page, "calcite-panel", { shadowed: true })).toBe(true); await page.keyboard.press("Tab"); @@ -644,8 +649,11 @@ describe("calcite-dialog", () => { await skipAnimations(page); const dialog = await page.find("calcite-dialog"); + const openEventSpy = await page.spyOnEvent("calciteDialogOpen"); dialog.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); + expect(await isElementFocused(page, `#${button1Id}`)).toBe(true); await page.keyboard.press("Tab"); @@ -669,8 +677,8 @@ describe("calcite-dialog", () => { open second dialog `); - let openEvent = page.waitForEvent("calciteDialogOpen"); await skipAnimations(page); + const openEventSpy = await page.spyOnEvent("calciteDialogOpen"); const dialog = await page.find("calcite-dialog"); dialog.setProperty("open", true); await page.waitForChanges(); @@ -689,11 +697,10 @@ describe("calcite-dialog", () => { }); }); await page.waitForChanges(); - await openEvent; + await openEventSpy.next(); - openEvent = page.waitForEvent("calciteDialogOpen"); await page.click("#openButton"); - await openEvent; + await openEventSpy.next(); expect(await isElementFocused(page, "#dialog2")).toBe(true); }); @@ -746,14 +753,14 @@ describe("calcite-dialog", () => { const page = await newE2EPage(); await page.setContent(``); await skipAnimations(page); - const openedEvent = page.waitForEvent("calciteDialogOpen"); + const openEventSpy = await page.spyOnEvent("calciteDialogOpen"); const dialog = await page.find("calcite-dialog"); const container = await page.find(`calcite-dialog >>> .${CSS.container}`); dialog.setProperty("open", true); await page.waitForChanges(); - await openedEvent; + await openEventSpy.next(); expect(await dialog.isVisible()).toBe(true); await page.keyboard.press("Escape"); @@ -768,7 +775,7 @@ describe("calcite-dialog", () => { it("closes when Escape key is pressed and dialog is open on page load", async () => { const page = await newProgrammaticE2EPage(); - const openEvent = page.waitForEvent("calciteDialogOpen"); + const openEventSpy = await page.spyOnEvent("calciteDialogOpen"); await page.evaluate(() => { const dialog = document.createElement("calcite-dialog"); dialog.open = true; @@ -778,7 +785,7 @@ describe("calcite-dialog", () => { const dialog = await page.find("calcite-dialog"); await page.waitForChanges(); expect(dialog).toHaveAttribute("open"); - await openEvent; + await openEventSpy.next(); await page.keyboard.press("Escape"); await page.waitForChanges(); @@ -795,12 +802,12 @@ describe("calcite-dialog", () => { await skipAnimations(page); const dialog = await page.find("calcite-dialog"); const container = await page.find(`calcite-dialog >>> .${CSS.container}`); - const openedEvent = page.waitForEvent("calciteDialogOpen"); + const openEventSpy = await page.spyOnEvent("calciteDialogOpen"); await page.waitForChanges(); dialog.setProperty("open", true); await page.waitForChanges(); - await openedEvent; + await openEventSpy.next(); expect(await container.isVisible()).toBe(true); const closeButton = await page.find(`calcite-dialog >>> calcite-panel >>> #${PanelIDS.close}`); @@ -1268,7 +1275,7 @@ describe("calcite-dialog", () => { beforeEach(async () => { page = await newProgrammaticE2EPage(); await skipAnimations(page); - const openEvent = page.waitForEvent("calciteDialogOpen"); + const openEventSpy = await page.spyOnEvent("calciteDialogOpen"); await page.evaluate((modal) => { const innerButton = document.createElement("button"); innerButton.id = "insideEl"; @@ -1287,7 +1294,7 @@ describe("calcite-dialog", () => { document.body.append(outsideButton); }, modal); await page.waitForChanges(); - await openEvent; + await openEventSpy.next(); await page.waitForChanges(); dialog = await page.find("calcite-dialog"); diff --git a/packages/calcite-components/src/components/dropdown-item/dropdown-item.e2e.ts b/packages/calcite-components/src/components/dropdown-item/dropdown-item.e2e.ts index 4691ad9551c..ba7ab24d05b 100644 --- a/packages/calcite-components/src/components/dropdown-item/dropdown-item.e2e.ts +++ b/packages/calcite-components/src/components/dropdown-item/dropdown-item.e2e.ts @@ -28,27 +28,25 @@ describe("calcite-dropdown-item", () => { const element = await page.find("calcite-dropdown-item"); const itemChangeSpy = await element.spyOnEvent("calciteDropdownItemSelect"); - let calciteDropdownItemSelectEvent: Promise; - - calciteDropdownItemSelectEvent = page.waitForEvent("calciteDropdownItemSelect"); + const calciteDropdownItemSelectEventSpy = await page.spyOnEvent("calciteDropdownItemSelect"); await element.click(); - await calciteDropdownItemSelectEvent; + await calciteDropdownItemSelectEventSpy.next(); expect(itemChangeSpy).toHaveReceivedEventTimes(1); - calciteDropdownItemSelectEvent = page.waitForEvent("calciteDropdownItemSelect"); await element.callMethod("setFocus"); await page.waitForChanges(); await page.keyboard.press("Enter"); - await calciteDropdownItemSelectEvent; + await page.waitForChanges(); + await calciteDropdownItemSelectEventSpy.next(); expect(itemChangeSpy).toHaveReceivedEventTimes(2); - calciteDropdownItemSelectEvent = page.waitForEvent("calciteDropdownItemSelect"); await element.callMethod("setFocus"); await page.waitForChanges(); await page.keyboard.press("Space"); - await calciteDropdownItemSelectEvent; + await page.waitForChanges(); + await calciteDropdownItemSelectEventSpy.next(); expect(itemChangeSpy).toHaveReceivedEventTimes(3); }); diff --git a/packages/calcite-components/src/components/dropdown/dropdown.e2e.ts b/packages/calcite-components/src/components/dropdown/dropdown.e2e.ts index 23b4922970c..93bb75d682c 100644 --- a/packages/calcite-components/src/components/dropdown/dropdown.e2e.ts +++ b/packages/calcite-components/src/components/dropdown/dropdown.e2e.ts @@ -510,9 +510,9 @@ describe("calcite-dropdown", () => { }); const element = await page.find("calcite-dropdown"); - const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); + const openEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await element.click(); - await dropdownOpenEvent; + await openEventSpy.next(); expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-1"); }); @@ -530,9 +530,9 @@ describe("calcite-dropdown", () => { }); const element = await page.find("calcite-dropdown"); - const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); + const dropdownOpenEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await element.click(); - await dropdownOpenEvent; + await dropdownOpenEventSpy.next(); expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-3"); }); @@ -551,9 +551,9 @@ describe("calcite-dropdown", () => { }); const element = await page.find("calcite-dropdown"); - const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); + const dropdownOpenEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await element.click(); - await dropdownOpenEvent; + await dropdownOpenEventSpy.next(); expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-2"); }); @@ -612,9 +612,9 @@ describe("calcite-dropdown", () => { await page.waitForChanges(); const element = await page.find("calcite-dropdown"); - const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); + const dropdownOpenEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await element.click(); - await dropdownOpenEvent; + await dropdownOpenEventSpy.next(); expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-50"); @@ -647,9 +647,9 @@ describe("calcite-dropdown", () => { ); const element = await page.find("calcite-dropdown"); - const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); + const dropdownOpenEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await element.click(); - await dropdownOpenEvent; + await dropdownOpenEventSpy.next(); const items = await findAll(page, "calcite-dropdown-item"); @@ -783,32 +783,34 @@ describe("calcite-dropdown", () => { 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); + + const openEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await trigger.click(); await page.waitForChanges(); + await openEventSpy.next(); + expect(await dropdownWrapper.isVisible()).toBe(true); - await waitForCalciteDropdownOpen; expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); expect(calciteDropdownClose).toHaveReceivedEventTimes(0); await element.callMethod("setFocus"); await page.waitForChanges(); + const closeEventSpy = await page.spyOnEvent("calciteDropdownClose"); await page.keyboard.press("Space"); await page.waitForChanges(); + await closeEventSpy.next(); + 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(); + await openEventSpy.next(); + expect(await dropdownWrapper.isVisible()).toBe(true); - await waitForCalciteDropdownOpen; expect(calciteDropdownOpen).toHaveReceivedEventTimes(2); expect(calciteDropdownClose).toHaveReceivedEventTimes(1); }); @@ -830,32 +832,34 @@ describe("calcite-dropdown", () => { 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); + + const openEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await trigger.click(); await page.waitForChanges(); + await openEventSpy.next(); + expect(await dropdownWrapper.isVisible()).toBe(true); - await waitForCalciteDropdownOpen; expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); expect(calciteDropdownClose).toHaveReceivedEventTimes(0); await element.callMethod("setFocus"); await page.waitForChanges(); + const closeEventSpy = await page.spyOnEvent("calciteDropdownClose"); await page.keyboard.press("Space"); await page.waitForChanges(); + await closeEventSpy.next(); + 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(); + await openEventSpy.next(); + expect(await dropdownWrapper.isVisible()).toBe(true); - await waitForCalciteDropdownOpen; expect(calciteDropdownOpen).toHaveReceivedEventTimes(2); expect(calciteDropdownClose).toHaveReceivedEventTimes(1); }); @@ -876,7 +880,7 @@ describe("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"); + const openEventSpy = await page.spyOnEvent("calciteDropdownOpen"); expect(await dropdownWrapper.isVisible()).toBe(false); @@ -886,8 +890,9 @@ describe("calcite-dropdown", () => { }); await page.waitForChanges(); + await openEventSpy.next(); + expect(await dropdownWrapper.isVisible()).toBe(true); - await waitForCalciteDropdownOpen; expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); expect(calciteDropdownClose).toHaveReceivedEventTimes(0); }); @@ -913,15 +918,22 @@ describe("calcite-dropdown", () => { const calciteDropdownOpen = await element.spyOnEvent("calciteDropdownOpen"); expect(await dropdownWrapper.isVisible()).toBe(false); + + const openEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await trigger.click(); await page.waitForChanges(); + await openEventSpy.next(); + expect(await dropdownWrapper.isVisible()).toBe(true); expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); expect(calciteDropdownClose).toHaveReceivedEventTimes(0); expect(await getFocusedElementProp(page, "id")).toBe("item-2"); + const closeEventSpy = await page.spyOnEvent("calciteDropdownClose"); await element.press("Tab"); await page.waitForChanges(); + await closeEventSpy.next(); + expect(await getFocusedElementProp(page, "id")).toBe("button-1"); expect(calciteDropdownClose).toHaveReceivedEventTimes(1); expect(await dropdownWrapper.isVisible()).toBe(false); @@ -946,17 +958,24 @@ describe("calcite-dropdown", () => { const calciteDropdownOpen = await element.spyOnEvent("calciteDropdownOpen"); expect(await dropdownWrapper.isVisible()).toBe(false); + + const openEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await trigger.click(); await page.waitForChanges(); + await openEventSpy.next(); + expect(await dropdownWrapper.isVisible()).toBe(true); expect(calciteDropdownOpen).toHaveReceivedEventTimes(1); expect(calciteDropdownClose).toHaveReceivedEventTimes(0); expect(await getFocusedElementProp(page, "id")).toBe("item-2"); + const closeEventSpy = await page.spyOnEvent("calciteDropdownClose"); await page.keyboard.down("Shift"); await element.press("Tab"); await page.keyboard.up("Shift"); await page.waitForChanges(); + await closeEventSpy.next(); + expect(await getFocusedElementProp(page, "id")).toBe("trigger"); expect(calciteDropdownClose).toHaveReceivedEventTimes(1); expect(await dropdownWrapper.isVisible()).toBe(false); @@ -1268,8 +1287,10 @@ describe("calcite-dropdown", () => { await dropdown.callMethod("setFocus"); await page.waitForChanges(); + const openEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await page.keyboard.press("Enter"); await page.waitForChanges(); + await openEventSpy.next(); expect(await isElementFocused(page, "#item-1")).toBe(true); @@ -1330,8 +1351,10 @@ describe("calcite-dropdown", () => { await dropdown.callMethod("setFocus"); await page.waitForChanges(); + const openEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await page.keyboard.press("Enter"); await page.waitForChanges(); + await openEventSpy.next(); expect(await isElementFocused(page, "#item-2")).toBe(true); @@ -1379,8 +1402,11 @@ describe("calcite-dropdown", () => { await dropdown.callMethod("setFocus"); await page.waitForChanges(); + const openEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await page.keyboard.press("ArrowDown"); await page.waitForChanges(); + await openEventSpy.next(); + expect(await dropdown.getProperty("open")).toBe(true); expect(await isElementFocused(page, "#item-1")).toBe(true); @@ -1411,8 +1437,11 @@ describe("calcite-dropdown", () => { await dropdown.callMethod("setFocus"); await page.waitForChanges(); + const openEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await page.keyboard.press("ArrowUp"); await page.waitForChanges(); + await openEventSpy.next(); + expect(await dropdown.getProperty("open")).toBe(true); expect(await isElementFocused(page, "#item-3")).toBe(true); @@ -1443,8 +1472,11 @@ describe("calcite-dropdown", () => { await dropdown.callMethod("setFocus"); await page.waitForChanges(); + const openEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await page.keyboard.press("ArrowDown"); await page.waitForChanges(); + await openEventSpy.next(); + expect(await dropdown.getProperty("open")).toBe(true); expect(await isElementFocused(page, "#item-2")).toBe(true); @@ -1475,8 +1507,11 @@ describe("calcite-dropdown", () => { await dropdown.callMethod("setFocus"); await page.waitForChanges(); + const openEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await page.keyboard.press("ArrowUp"); await page.waitForChanges(); + await openEventSpy.next(); + expect(await dropdown.getProperty("open")).toBe(true); expect(await isElementFocused(page, "#item-2")).toBe(true); diff --git a/packages/calcite-components/src/components/dropdown/dropdown.tsx b/packages/calcite-components/src/components/dropdown/dropdown.tsx index 1fa72c01f47..496824dbec7 100644 --- a/packages/calcite-components/src/components/dropdown/dropdown.tsx +++ b/packages/calcite-components/src/components/dropdown/dropdown.tsx @@ -495,11 +495,11 @@ export class Dropdown } onBeforeOpen(): void { + this.focusOnFirstActiveOrDefaultItem(); this.calciteDropdownBeforeOpen.emit(); } - async onOpen(): Promise { - this.focusOnFirstActiveOrDefaultItem(); + onOpen(): void { this.calciteDropdownOpen.emit(); } diff --git a/packages/calcite-components/src/components/filter/filter.e2e.ts b/packages/calcite-components/src/components/filter/filter.e2e.ts index 4163fb24779..8e8e6a797f1 100644 --- a/packages/calcite-components/src/components/filter/filter.e2e.ts +++ b/packages/calcite-components/src/components/filter/filter.e2e.ts @@ -232,11 +232,11 @@ describe("calcite-filter", () => { "regex", ]); - const filterChangeEvent = page.waitForEvent("calciteFilterChange"); + const filterChangeEventSpy = await page.spyOnEvent("calciteFilterChange"); await filter.callMethod("setFocus"); await page.waitForChanges(); await filter.type("developer"); - await filterChangeEvent; + await filterChangeEventSpy.next(); expect(filterChangeSpy).toHaveReceivedEventTimes(1); assertMatchingItems(await filter.getProperty("filteredItems"), ["harry", "matt", "franco", "jon"]); @@ -260,25 +260,25 @@ describe("calcite-filter", () => { }); it("searches recursively in items and works and matches on a partial string ignoring case", async () => { - const waitForEvent = page.waitForEvent("calciteFilterChange"); + const waitForEventSpy = await page.spyOnEvent("calciteFilterChange"); const filter = await page.find("calcite-filter"); await filter.callMethod("setFocus"); await page.waitForChanges(); await filter.type("volt"); - await waitForEvent; + await waitForEventSpy.next(); assertMatchingItems(await filter.getProperty("filteredItems"), ["franco"]); }); it("should escape regex", async () => { - const waitForEvent = page.waitForEvent("calciteFilterChange"); + const waitForEventSpy = await page.spyOnEvent("calciteFilterChange"); const filter = await page.find("calcite-filter"); await filter.callMethod("setFocus"); await page.waitForChanges(); await filter.type("regex()"); - await waitForEvent; + await waitForEventSpy.next(); assertMatchingItems(await filter.getProperty("filteredItems"), ["regex"]); }); diff --git a/packages/calcite-components/src/components/handle/handle.e2e.ts b/packages/calcite-components/src/components/handle/handle.e2e.ts index dc671ff64c7..560fb557cf4 100644 --- a/packages/calcite-components/src/components/handle/handle.e2e.ts +++ b/packages/calcite-components/src/components/handle/handle.e2e.ts @@ -109,19 +109,24 @@ describe("calcite-handle", () => { it("fires calciteHandleNudge event when focused and up or down key is pressed", async () => { const page = await newE2EPage(); await page.setContent(""); - + const handle = await page.find(`calcite-handle`); + const nudgeEventSpy = await handle.spyOnEvent("calciteHandleNudge"); const calciteHandleNudgeSpy = await page.spyOnEvent("calciteHandleNudge"); - const button = await page.find(`calcite-handle >>> .${CSS.handle}`); - - await button.focus(); - + await handle.callMethod("setFocus"); await page.keyboard.press(" "); + await page.waitForChanges(); await page.keyboard.press("ArrowUp"); - expect(await calciteHandleNudgeSpy.lastEvent.detail.direction).toBe("up"); + await page.waitForChanges(); + await nudgeEventSpy.next(); + + expect(calciteHandleNudgeSpy.lastEvent.detail.direction).toBe("up"); await page.keyboard.press("ArrowDown"); - expect(await calciteHandleNudgeSpy.lastEvent.detail.direction).toBe("down"); + await page.waitForChanges(); + await nudgeEventSpy.next(); + + expect(calciteHandleNudgeSpy.lastEvent.detail.direction).toBe("down"); expect(calciteHandleNudgeSpy).toHaveReceivedEventTimes(2); }); diff --git a/packages/calcite-components/src/components/icon/icon.e2e.ts b/packages/calcite-components/src/components/icon/icon.e2e.ts index b9aaf413068..aa11d7e6895 100644 --- a/packages/calcite-components/src/components/icon/icon.e2e.ts +++ b/packages/calcite-components/src/components/icon/icon.e2e.ts @@ -84,6 +84,9 @@ describe("calcite-icon", () => { expect(path.getAttribute("d")).toBeFalsy(); icon.setProperty("style", null); + + // intentional double waitForChanges to ensure the icon is loaded (sequenced prop updates) + await page.waitForChanges(); await page.waitForChanges(); expect(path.getAttribute("d")).toBeTruthy(); diff --git a/packages/calcite-components/src/components/inline-editable/inline-editable.e2e.ts b/packages/calcite-components/src/components/inline-editable/inline-editable.e2e.ts index 895613bc512..42a22735967 100644 --- a/packages/calcite-components/src/components/inline-editable/inline-editable.e2e.ts +++ b/packages/calcite-components/src/components/inline-editable/inline-editable.e2e.ts @@ -5,6 +5,7 @@ import { accessible, disabled, hidden, labelable, renders, t9n, themed } from ". import { html } from "../../../support/formatting"; import type { Input } from "../input/input"; import { findAll } from "../../tests/utils/puppeteer"; +import { createControlledPromise } from "../../tests/utils/promises"; import { CSS } from "./resources"; import type { InlineEditable } from "./inline-editable"; @@ -222,9 +223,9 @@ describe("calcite-inline-editable", () => { }); await input.type("-typo"); expect(await input.getProperty("value")).toBe("John Doe-typo"); - const cancelEvent = page.waitForEvent("calciteInlineEditableEditCancel"); + const cancelEventSpy = await page.spyOnEvent("calciteInlineEditableEditCancel"); await cancelEditingButton.click(); - await cancelEvent; + await cancelEventSpy.next(); expect(await input.getProperty("value")).toBe("John Doe"); expect(calciteInlineEditableEditCancel).toHaveReceivedEventTimes(1); expect(await element.getProperty("editingEnabled")).toBe(false); @@ -304,7 +305,8 @@ describe("calcite-inline-editable", () => { it("disables editing when afterConfirm resolves successfully", async () => { const element = await page.find("calcite-inline-editable"); - const afterConfirm: () => Promise = () => new Promise((resolve) => global.setTimeout(resolve, 100)); + const { promise, resolve } = createControlledPromise(); + const afterConfirm = () => promise; // https://github.com/ionic-team/stencil/issues/1174 await page.exposeFunction("afterConfirm", afterConfirm); await page.$eval("calcite-inline-editable", (el: InlineEditable["el"]) => { @@ -314,15 +316,19 @@ describe("calcite-inline-editable", () => { const input = await page.find("calcite-input"); const enableEditingButton = await page.find(`calcite-inline-editable >>> .${CSS.enableEditingButton}`); await enableEditingButton.click(); - const confirmChangesButton = await page.find("calcite-inline-editable >>> .confirm-changes-button"); + const confirmChangesButton = await page.find(`calcite-inline-editable >>> .${CSS.confirmChangesButton}`); await page.$eval("calcite-input", (element: Input["el"]): void => { const input = element.shadowRoot.querySelector("input"); input.setSelectionRange(input.value.length, input.value.length); }); await input.type("Moe"); + const confirmEventSpy = await page.spyOnEvent("calciteInlineEditableEditConfirm"); await confirmChangesButton.click(); - expect(calciteInlineEditableEditConfirm).toHaveReceivedEventTimes(1); + resolve(); await page.waitForChanges(); + await confirmEventSpy.next(); + await afterConfirm; + expect(calciteInlineEditableEditConfirm).toHaveReceivedEventTimes(1); expect(await input.getProperty("value")).toBe("John DoeMoe"); expect(element).not.toHaveAttribute("editing-enabled"); }); diff --git a/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts b/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts index 23f2eddd1cf..62073aa3b28 100644 --- a/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts +++ b/packages/calcite-components/src/components/input-date-picker/input-date-picker.e2e.ts @@ -625,10 +625,10 @@ describe("calcite-input-date-picker", () => { ``, ); const inputDatePicker = await page.find("calcite-input-date-picker"); - const calciteInputDatePickerOpenEvent = page.waitForEvent("calciteInputDatePickerOpen"); + const calciteInputDatePickerOpenEventSpy = await page.spyOnEvent("calciteInputDatePickerOpen"); await inputDatePicker.click(); - await calciteInputDatePickerOpenEvent; + await calciteInputDatePickerOpenEventSpy.next(); await selectDayInMonthByIndex(page, 1); await inputDatePicker.callMethod("blur"); @@ -974,9 +974,9 @@ describe("calcite-input-date-picker", () => { expect(await getFocusedElementProp(page, "tagName")).toBe("CALCITE-INPUT-DATE-PICKER"); expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-INPUT-TEXT"); - const opening = page.waitForEvent("calciteInputDatePickerOpen"); + const openEventSpy = await page.spyOnEvent("calciteInputDatePickerOpen"); await page.keyboard.press("ArrowDown"); - await opening; + await openEventSpy.next(); expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-DATE-PICKER"); await page.keyboard.down("Shift"); @@ -987,9 +987,9 @@ describe("calcite-input-date-picker", () => { await page.keyboard.press("Tab"); expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-DATE-PICKER"); - const closing = page.waitForEvent("calciteInputDatePickerClose"); + const closeEventSpy = await page.spyOnEvent("calciteInputDatePickerClose"); await page.keyboard.press("Escape"); - await closing; + await closeEventSpy.next(); expect(await getFocusedElementProp(page, "tagName")).toBe("CALCITE-INPUT-DATE-PICKER"); expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-INPUT-TEXT"); @@ -1024,9 +1024,9 @@ describe("calcite-input-date-picker", () => { expect(await getFocusedElementProp(page, "tagName")).toBe("CALCITE-INPUT-DATE-PICKER"); expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-INPUT-TEXT"); - const startOpening = page.waitForEvent("calciteInputDatePickerOpen"); + const openEventSpy = await page.spyOnEvent("calciteInputDatePickerOpen"); await page.keyboard.press("ArrowDown"); - await startOpening; + await openEventSpy.next(); expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-DATE-PICKER"); await page.keyboard.down("Shift"); @@ -1037,9 +1037,9 @@ describe("calcite-input-date-picker", () => { await page.keyboard.press("Tab"); expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-DATE-PICKER"); - const startClosing = page.waitForEvent("calciteInputDatePickerClose"); + const closeEventSpy = await page.spyOnEvent("calciteInputDatePickerClose"); await page.keyboard.press("Escape"); - await startClosing; + await closeEventSpy.next(); expect(await getFocusedElementProp(page, "tagName")).toBe("CALCITE-INPUT-DATE-PICKER"); expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-INPUT-TEXT"); @@ -1047,9 +1047,8 @@ describe("calcite-input-date-picker", () => { expect(await getFocusedElementProp(page, "tagName")).toBe("CALCITE-INPUT-DATE-PICKER"); expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-INPUT-TEXT"); - const endOpening = page.waitForEvent("calciteInputDatePickerOpen"); await page.keyboard.press("ArrowDown"); - await endOpening; + await openEventSpy.next(); expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-DATE-PICKER"); await page.keyboard.down("Shift"); @@ -1060,9 +1059,8 @@ describe("calcite-input-date-picker", () => { await page.keyboard.press("Tab"); expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-DATE-PICKER"); - const endClosing = page.waitForEvent("calciteInputDatePickerClose"); await page.keyboard.press("Escape"); - await endClosing; + await closeEventSpy.next(); expect(await getFocusedElementProp(page, "tagName")).toBe("CALCITE-INPUT-DATE-PICKER"); expect(await getFocusedElementProp(page, "tagName", { shadow: true })).toBe("CALCITE-INPUT-TEXT"); diff --git a/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts b/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts index 97bc492860c..9a241f302f2 100644 --- a/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts +++ b/packages/calcite-components/src/components/input-time-picker/input-time-picker.e2e.ts @@ -1543,8 +1543,9 @@ describe("calcite-input-time-picker", () => { expect(await isElementFocused(page, "calcite-input-time-picker")).toBe(true); + const openEventSpy = await page.spyOnEvent("calciteInputTimePickerOpen"); await toggleButton.click(); - await page.waitForChanges(); + await openEventSpy.next(); expect(await popoverPositionContainer.isVisible()).toBe(true); @@ -1566,8 +1567,10 @@ describe("calcite-input-time-picker", () => { expect(await isElementFocused(page, "calcite-time-picker", { shadowed: true })).toBe(true); + const closeEventSpy = await page.spyOnEvent("calciteInputTimePickerClose"); await page.keyboard.press("Escape"); await page.waitForChanges(); + await closeEventSpy.next(); expect(await popoverPositionContainer.isVisible()).toBe(false); expect(await isElementFocused(page, "calcite-input-time-picker")).toBe(true); @@ -1607,13 +1610,15 @@ describe("calcite-input-time-picker", () => { expect(await popoverPositionContainer.isVisible()).toBe(false); + const openEventSpy = await page.spyOnEvent("calciteInputTimePickerOpen"); await toggleButton.click(); - await page.waitForChanges(); + await openEventSpy.next(); expect(await popoverPositionContainer.isVisible()).toBe(true); + const closeEventSpy = await page.spyOnEvent("calciteInputTimePickerClose"); await toggleButton.click(); - await page.waitForChanges(); + await closeEventSpy.next(); expect(await popoverPositionContainer.isVisible()).toBe(false); }); diff --git a/packages/calcite-components/src/components/list/list.e2e.ts b/packages/calcite-components/src/components/list/list.e2e.ts index 710d9effd1b..d4e1dc9e37b 100755 --- a/packages/calcite-components/src/components/list/list.e2e.ts +++ b/packages/calcite-components/src/components/list/list.e2e.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { E2EElement, E2EPage, newE2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; +import { E2EPage, newE2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; import { describe, expect, it } from "vitest"; import { accessible, @@ -570,11 +570,11 @@ describe("calcite-list", () => { await filter.callMethod("setFocus"); await page.waitForChanges(); - const calciteListFilterEvent = list.waitForEvent("calciteListFilter"); + const calciteListFilterEventSpy = await list.spyOnEvent("calciteListFilter"); await page.keyboard.type("one"); await page.waitForChanges(); await page.waitForTimeout(DEBOUNCE.filter); - await calciteListFilterEvent; + await calciteListFilterEventSpy.next(); expect(eventSpy).toHaveReceivedEventTimes(0); expect(await list.getProperty("filteredItems")).toHaveLength(1); expect(await list.getProperty("filteredData")).toHaveLength(1); @@ -593,11 +593,10 @@ describe("calcite-list", () => { await page.keyboard.press("Backspace"); await page.waitForChanges(); - const calciteListFilterEvent2 = list.waitForEvent("calciteListFilter"); await page.keyboard.type("two"); await page.waitForChanges(); await page.waitForTimeout(DEBOUNCE.filter); - await calciteListFilterEvent2; + await calciteListFilterEventSpy.next(); expect(eventSpy).toHaveReceivedEventTimes(0); expect(await list.getProperty("filteredItems")).toHaveLength(1); expect(await list.getProperty("filteredData")).toHaveLength(1); @@ -611,11 +610,10 @@ describe("calcite-list", () => { expect(await items[1].getProperty("setPosition")).toBe(1); expect(await items[1].getProperty("setSize")).toBe(1); - const calciteListFilterEvent3 = list.waitForEvent("calciteListFilter"); await page.keyboard.type(" blah"); await page.waitForChanges(); await page.waitForTimeout(DEBOUNCE.filter); - await calciteListFilterEvent3; + await calciteListFilterEventSpy.next(); expect(eventSpy).toHaveReceivedEventTimes(0); expect(await list.getProperty("filteredItems")).toHaveLength(0); expect(await list.getProperty("filteredData")).toHaveLength(0); @@ -1176,16 +1174,15 @@ describe("calcite-list", () => { `calcite-list-item[value=one] >>> .${ListItemCSS.contentContainer}`, ); - const calciteListChangeEvent = list.waitForEvent("calciteListChange"); + const calciteListChangeEventSpy = await list.spyOnEvent("calciteListChange"); await listItemOneContentContainer.click(); - await calciteListChangeEvent; + await calciteListChangeEventSpy.next(); expect(await listItemOne.getProperty("selected")).toBe(true); expect(await list.getProperty("selectedItems")).toHaveLength(1); - const calciteListChangeEvent2 = list.waitForEvent("calciteListChange"); await listItemOneContentContainer.click(); - await calciteListChangeEvent2; + await calciteListChangeEventSpy.next(); expect(await listItemOne.getProperty("selected")).toBe(false); expect(await list.getProperty("selectedItems")).toHaveLength(0); @@ -1954,7 +1951,7 @@ describe("calcite-list", () => { ): Promise { const component = await page.find("calcite-list"); const eventName = `calciteSortHandleReorder`; - const event = component.waitForEvent(eventName); + const eventSpy = await component.spyOnEvent(eventName); await page.$eval( `calcite-list-item[value="one"]`, (item1: ListItem["el"], reorder, eventName) => { @@ -1963,8 +1960,8 @@ describe("calcite-list", () => { reorder, eventName, ); - await event; await page.waitForChanges(); + await eventSpy.next(); const itemsAfter = await findAll(page, "calcite-list-item"); expect(itemsAfter.length).toBe(3); @@ -2082,6 +2079,7 @@ describe("calcite-list", () => { ): Promise { const component = await page.find(`#${listItemId}`); const eventName = `calciteSortHandleMove`; + // eslint-disable-next-line no-restricted-properties -- workaround for spyOnEvent throwing errors due to circular JSON structures when serializing the event payload const event = component.waitForEvent(eventName); await page.$eval( `#${listItemId}`, @@ -2271,6 +2269,8 @@ describe("calcite-list", () => { async function assertDescendantItems(page: E2EPage, groupSelector: string, visibility: boolean): Promise { const items = await findAll(page, `calcite-list-item-group${groupSelector} > calcite-list-item`); - items.forEach(async (item: E2EElement) => expect(await item.isVisible()).toBe(visibility)); + for (const item of items) { + expect(await item.isVisible()).toBe(visibility); + } } }); diff --git a/packages/calcite-components/src/components/meter/meter.e2e.ts b/packages/calcite-components/src/components/meter/meter.e2e.ts index 846c4d04245..2e789a21323 100644 --- a/packages/calcite-components/src/components/meter/meter.e2e.ts +++ b/packages/calcite-components/src/components/meter/meter.e2e.ts @@ -102,10 +102,9 @@ describe("calcite-meter", () => { describe("correctly sets range and value properties", () => { it("correctly sets range and value properties if not present", async () => { const page = await newE2EPage({ - html: html``, + html: html``, }); const meter = await page.find(`calcite-meter`); - page.waitForChanges(); expect(await meter.getProperty("min")).toBe(0); expect(await meter.getProperty("max")).toBe(100); expect(await meter.getProperty("low")).toBe(0); @@ -115,10 +114,9 @@ describe("calcite-meter", () => { it("correctly sets range and value properties if not present and non-default min / max set", async () => { const page = await newE2EPage({ - html: html``, + html: html``, }); const meter = await page.find(`calcite-meter`); - page.waitForChanges(); expect(await meter.getProperty("min")).toBe(2000); expect(await meter.getProperty("max")).toBe(10000); expect(await meter.getProperty("low")).toBe(2000); @@ -128,10 +126,9 @@ describe("calcite-meter", () => { it("correctly adjusts out of range low and high", async () => { const page = await newE2EPage({ - html: html``, + html: html``, }); const meter = await page.find(`calcite-meter`); - page.waitForChanges(); expect(await meter.getProperty("min")).toBe(10); expect(await meter.getProperty("max")).toBe(25); expect(await meter.getProperty("low")).toBe(10); @@ -141,7 +138,7 @@ describe("calcite-meter", () => { it("correctly adjusts out of range low and high - b", async () => { const page = await newE2EPage({ - html: html``, + html: html``, }); const meter = await page.find(`calcite-meter`); page.waitForChanges(); @@ -154,10 +151,9 @@ describe("calcite-meter", () => { it("correctly leaves out of range value", async () => { const page = await newE2EPage({ - html: html``, + html: html``, }); const meter = await page.find(`calcite-meter`); - page.waitForChanges(); expect(await meter.getProperty("min")).toBe(10); expect(await meter.getProperty("max")).toBe(25); expect(await meter.getProperty("low")).toBe(10); @@ -165,10 +161,10 @@ describe("calcite-meter", () => { expect(await meter.getProperty("value")).toBe(210); }); }); + describe("theme", () => { themed( html` { expect(styleH).toEqual("800px"); }); - it("calls the beforeClose method prior to closing via click", async () => { - const page = await newE2EPage(); - const mockCallBack = vi.fn(); - await page.exposeFunction("beforeClose", mockCallBack); - await page.setContent(` - - `); - const modal = await page.find("calcite-modal"); - await page.$eval( - "calcite-modal", - (el: Modal["el"]) => - (el.beforeClose = (window as GlobalTestProps<{ beforeClose: Modal["el"]["beforeClose"] }>).beforeClose), - ); - await page.waitForChanges(); - modal.setProperty("open", true); - await page.waitForChanges(); - expect(await modal.getProperty("opened")).toBe(true); - const closeButton = await page.find(`calcite-modal >>> .${CSS.close}`); - await closeButton.click(); - await page.waitForChanges(); - expect(mockCallBack).toHaveBeenCalledTimes(1); - expect(await modal.getProperty("opened")).toBe(false); - }); + describe("beforeClose", () => { + let page: E2EPage; + let modal: E2EElement; - it("calls the beforeClose method prior to closing via ESC key", async () => { - const page = await newE2EPage(); - const mockCallBack = vi.fn(); - await page.exposeFunction("beforeClose", mockCallBack); - await page.setContent(` - - `); - const modal = await page.find("calcite-modal"); - await page.$eval( - "calcite-modal", - (el: Modal["el"]) => - (el.beforeClose = (window as GlobalTestProps<{ beforeClose: Modal["el"]["beforeClose"] }>).beforeClose), - ); - await skipAnimations(page); - await page.waitForChanges(); + beforeEach(async () => { + page = await newE2EPage(); + await page.setContent(html``); + await skipAnimations(page); + modal = await page.find("calcite-modal"); + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); + modal.setProperty("open", true); + await page.waitForChanges(); + await openEventSpy.next(); + }); - modal.setProperty("open", true); - await page.waitForChanges(); - expect(await modal.getProperty("opened")).toBe(true); + it("calls the beforeClose method prior to closing via click", async () => { + const mockCallBack = vi.fn(); + await page.exposeFunction("beforeClose", mockCallBack); + await page.$eval( + "calcite-modal", + (el: Modal["el"]) => + (el.beforeClose = (window as GlobalTestProps<{ beforeClose: Modal["el"]["beforeClose"] }>).beforeClose), + ); + await page.waitForChanges(); - await page.keyboard.press("Escape"); - await page.waitForChanges(); - expect(mockCallBack).toHaveBeenCalledTimes(1); - expect(await modal.getProperty("opened")).toBe(false); - }); + expect(await modal.getProperty("opened")).toBe(true); - it("calls the beforeClose method prior to closing via attribute", async () => { - const page = await newE2EPage(); - const mockCallBack = vi.fn(); - await page.exposeFunction("beforeClose", mockCallBack); - await page.setContent(` - - `); - const modal = await page.find("calcite-modal"); - await page.$eval( - "calcite-modal", - (el: Modal["el"]) => - (el.beforeClose = (window as GlobalTestProps<{ beforeClose: Modal["el"]["beforeClose"] }>).beforeClose), - ); - await page.waitForChanges(); - modal.setProperty("open", true); - await page.waitForChanges(); - expect(await modal.getProperty("opened")).toBe(true); - modal.removeAttribute("open"); - await page.waitForChanges(); - expect(mockCallBack).toHaveBeenCalledTimes(1); - expect(await modal.getProperty("opened")).toBe(false); - }); + const closeButton = await page.find(`calcite-modal >>> .${CSS.close}`); + await closeButton.click(); - it("should handle rejected 'beforeClose' promise'", async () => { - const page = await newE2EPage(); + expect(mockCallBack).toHaveBeenCalledTimes(1); + expect(await modal.getProperty("opened")).toBe(false); + }); - const mockCallBack = vi.fn().mockReturnValue(() => Promise.reject()); - await page.exposeFunction("beforeClose", mockCallBack); + it("calls the beforeClose method prior to closing via ESC key", async () => { + const mockCallBack = vi.fn(); + await page.exposeFunction("beforeClose", mockCallBack); + await page.$eval( + "calcite-modal", + (el: Modal["el"]) => + (el.beforeClose = (window as GlobalTestProps<{ beforeClose: Modal["el"]["beforeClose"] }>).beforeClose), + ); + await page.waitForChanges(); - await page.setContent(``); + expect(await modal.getProperty("opened")).toBe(true); - await page.$eval( - "calcite-modal", - (elm: Modal["el"]) => (elm.beforeClose = (window as typeof window & Pick).beforeClose), - ); + await page.keyboard.press("Escape"); + await page.waitForChanges(); - const modal = await page.find("calcite-modal"); - modal.setProperty("open", false); - await page.waitForChanges(); + expect(mockCallBack).toHaveBeenCalledTimes(1); + expect(await modal.getProperty("opened")).toBe(false); + }); - expect(mockCallBack).toHaveBeenCalledTimes(1); - }); + it("calls the beforeClose method prior to closing via attribute", async () => { + const mockCallBack = vi.fn(); + await page.exposeFunction("beforeClose", mockCallBack); + await page.$eval( + "calcite-modal", + (el: Modal["el"]) => + (el.beforeClose = (window as GlobalTestProps<{ beforeClose: Modal["el"]["beforeClose"] }>).beforeClose), + ); + await page.waitForChanges(); - it("should remain open with rejected 'beforeClose' promise'", async () => { - const page = await newE2EPage(); + expect(await modal.getProperty("opened")).toBe(true); - await page.exposeFunction("beforeClose", () => Promise.reject()); - await page.setContent(``); + modal.removeAttribute("open"); + await page.waitForChanges(); - await page.$eval( - "calcite-modal", - (elm: Modal["el"]) => (elm.beforeClose = (window as typeof window & Pick).beforeClose), - ); + expect(mockCallBack).toHaveBeenCalledTimes(1); + expect(await modal.getProperty("opened")).toBe(false); + }); - const modal = await page.find("calcite-modal"); - modal.setProperty("open", false); - await page.waitForChanges(); + it("should handle rejected 'beforeClose' promise'", async () => { + const mockCallBack = vi.fn().mockReturnValue(() => Promise.reject()); + await page.exposeFunction("beforeClose", mockCallBack); + await page.$eval( + "calcite-modal", + (elm: Modal["el"]) => + (elm.beforeClose = (window as typeof window & Pick).beforeClose), + ); + await page.waitForChanges(); - expect(await modal.getProperty("open")).toBe(true); - expect(await modal.getProperty("opened")).toBe(true); - expect(modal.getAttribute("open")).toBe(""); // Makes sure attribute is added back + modal.setProperty("open", false); + await page.waitForChanges(); + + expect(mockCallBack).toHaveBeenCalledTimes(1); + }); + + it("should remain open with rejected 'beforeClose' promise'", async () => { + await page.exposeFunction("beforeClose", () => Promise.reject()); + await page.$eval( + "calcite-modal", + (elm: Modal["el"]) => + (elm.beforeClose = (window as typeof window & Pick).beforeClose), + ); + await page.waitForChanges(); + + modal.setProperty("open", false); + await page.waitForChanges(); + + expect(await modal.getProperty("open")).toBe(true); + expect(await modal.getProperty("opened")).toBe(true); + expect(modal.getAttribute("open")).toBe(""); // Makes sure attribute is added back + }); }); describe("calcite-modal accessibility checks", () => { @@ -273,11 +266,12 @@ describe("calcite-modal", () => { `, ); + await skipAnimations(page); const modal = await page.find("calcite-modal"); - const opened = page.waitForEvent("calciteModalOpen"); + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); modal.setProperty("open", true); await page.waitForChanges(); - await opened; + await openEventSpy.next(); expect(await isElementFocused(page, `.${CSS.close}`, { shadowed: true })).toBe(true); await page.keyboard.press("Tab"); @@ -329,9 +323,11 @@ describe("calcite-modal", () => { ); await skipAnimations(page); const modal = await page.find("calcite-modal"); + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); await modal.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); expect(await isElementFocused(page, `#${button1Id}`)).toBe(true); await page.keyboard.press("Tab"); @@ -349,7 +345,7 @@ describe("calcite-modal", () => { it("subsequently opening a modal dynamically gets focus trapped", async () => { const page = await newProgrammaticE2EPage(); await skipAnimations(page); - let openEvent = page.waitForEvent("calciteModalOpen"); + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); await page.evaluate(() => { const modal = document.createElement("calcite-modal"); modal.open = true; @@ -382,12 +378,11 @@ describe("calcite-modal", () => { }); }); await page.waitForChanges(); - await openEvent; + await openEventSpy.next(); - openEvent = page.waitForEvent("calciteModalOpen"); await page.click("#openButton"); await page.waitForChanges(); - await openEvent; + await openEventSpy.next(); expect(await isElementFocused(page, "#modal2")).toBe(true); }); @@ -429,20 +424,23 @@ describe("calcite-modal", () => { await page.setContent(``); await skipAnimations(page); const modal = await page.find("calcite-modal"); - const openedEvent = page.waitForEvent("calciteModalOpen"); + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); modal.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); expect(await modal.isVisible()).toBe(true); + const closeEventSpy = await page.spyOnEvent("calciteModalClose"); await page.keyboard.press("Escape"); await page.waitForChanges(); + await closeEventSpy.next(); expect(await modal.isVisible()).toBe(false); expect(await modal.getProperty("open")).toBe(false); modal.setProperty("open", true); await page.waitForChanges(); - await openedEvent; + await openEventSpy.next(); expect(await modal.isVisible()).toBe(true); }); @@ -451,13 +449,17 @@ describe("calcite-modal", () => { await page.setContent(``); await skipAnimations(page); const modal = await page.find("calcite-modal"); + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); modal.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); expect(await modal.isVisible()).toBe(true); + const closeEventSpy = await page.spyOnEvent("calciteModalClose"); await page.keyboard.press("Escape"); await page.waitForChanges(); + await closeEventSpy.next(); expect(await modal.isVisible()).toBe(false); expect(await modal.getProperty("open")).toBe(false); }); @@ -466,16 +468,16 @@ describe("calcite-modal", () => { const page = await newE2EPage(); await page.setContent(``); await skipAnimations(page); - const openedEvent = page.waitForEvent("calciteModalOpen"); + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); const modal = await page.find("calcite-modal"); await page.waitForChanges(); - await openedEvent; + await openEventSpy.next(); expect(modal).toHaveAttribute("open"); await page.keyboard.press("Escape"); await page.waitForChanges(); - await waitForAnimationFrame(); + await waitForAnimationFrame(page); expect(modal).not.toHaveAttribute("open"); await modal.setProperty("open", true); @@ -504,36 +506,59 @@ describe("calcite-modal", () => { it("should close when the scrim is clicked", async () => { const page = await newE2EPage(); await page.setContent(``); + await skipAnimations(page); const modal = await page.find("calcite-modal"); + + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); modal.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); + expect(modal).toHaveAttribute("open"); + + const closeEventSpy = await page.spyOnEvent("calciteModalClose"); await page.$eval("calcite-modal", (el) => el.shadowRoot.querySelector("calcite-scrim").click()); await page.waitForChanges(); + await closeEventSpy.next(); + expect(await modal.getProperty("open")).toBe(false); }); it("should not close when the scrim is clicked", async () => { const page = await newE2EPage(); await page.setContent(``); + await skipAnimations(page); const modal = await page.find("calcite-modal"); + + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); modal.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); + expect(modal).toHaveAttribute("open"); + await page.$eval("calcite-modal", (el) => el.shadowRoot.querySelector("calcite-scrim").click()); await page.waitForChanges(); + expect(await modal.getProperty("open")).toBe(true); }); it("does not close when Escape is pressed and escape-disabled is set", async () => { const page = await newE2EPage(); await page.setContent(``); + await skipAnimations(page); const modal = await page.find("calcite-modal"); + + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); await modal.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); + expect(modal).toHaveAttribute("open"); + await page.keyboard.press("Escape"); await page.waitForChanges(); + expect(modal).toHaveAttribute("open"); }); @@ -545,15 +570,20 @@ describe("calcite-modal", () => { it("correctly sets overflow style on document when opened/closed", async () => { const page = await newE2EPage(); await page.setContent(``); + await skipAnimations(page); const modal = await page.find("calcite-modal"); + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); await modal.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); expect(await hasOverflowStyle(page)).toEqual(true); + const closeEventSpy = await page.spyOnEvent("calciteModalClose"); await modal.setProperty("open", false); await page.waitForChanges(); + await closeEventSpy.next(); expect(await hasOverflowStyle(page)).toEqual(false); }); @@ -561,16 +591,21 @@ describe("calcite-modal", () => { it("preserves existing overflow style when modal is opened/closed", async () => { const page = await newE2EPage(); await page.setContent(``); + await skipAnimations(page); await page.evaluate(() => (document.documentElement.style.overflow = "scroll")); const modal = await page.find("calcite-modal"); + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); await modal.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); expect(await hasOverflowStyle(page)).toEqual(true); + const closeEventSpy = await page.spyOnEvent("calciteModalClose"); await modal.setProperty("open", false); await page.waitForChanges(); + await closeEventSpy.next(); expect(await page.evaluate(() => document.documentElement.style.overflow)).toEqual("scroll"); }); @@ -578,10 +613,13 @@ describe("calcite-modal", () => { it("correctly does not add overflow style on document when open and slotted in shell modals slot", async () => { const page = await newE2EPage(); await page.setContent(``); + await skipAnimations(page); const modal = await page.find("calcite-modal"); + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); await modal.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); expect(await hasOverflowStyle(page)).toEqual(false); }); @@ -592,20 +630,27 @@ describe("calcite-modal", () => { `); + await skipAnimations(page); const modal1 = await page.find("#modal-1"); const modal2 = await page.find("#modal-2"); + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); await modal1.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); await modal2.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); expect(await hasOverflowStyle(page)).toEqual(true); + const closeEventSpy = await page.spyOnEvent("calciteModalClose"); await modal2.setProperty("open", false); await page.waitForChanges(); + await closeEventSpy.next(); await modal1.setProperty("open", false); await page.waitForChanges(); + await closeEventSpy.next(); expect(await hasOverflowStyle(page)).toEqual(false); }); @@ -616,20 +661,27 @@ describe("calcite-modal", () => { `); + await skipAnimations(page); const modal1 = await page.find("#modal-1"); const modal2 = await page.find("#modal-2"); + const openEventSpy = await page.spyOnEvent("calciteModalOpen"); await modal1.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); await modal2.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); expect(await hasOverflowStyle(page)).toEqual(true); + const closeEventSpy = await page.spyOnEvent("calciteModalClose"); await modal1.setProperty("open", false); await page.waitForChanges(); + await closeEventSpy.next(); await modal2.setProperty("open", false); await page.waitForChanges(); + await closeEventSpy.next(); expect(await hasOverflowStyle(page)).toEqual(false); }); @@ -642,6 +694,7 @@ describe("calcite-modal", () => { TEST `); + await skipAnimations(page); const footer = await page.find("calcite-modal >>> .footer"); expect(await footer.isVisible()).toBe(true); await page.$eval("calcite-button", (el) => el.parentElement.removeChild(el)); @@ -649,52 +702,10 @@ describe("calcite-modal", () => { expect(await footer.isVisible()).toBe(false); }); - it("should render calcite-scrim with default background color", async () => { - const page = await newE2EPage({ - html: ` - - -
The actual content of the modal
- - Back - - Cancel - Save -
- `, - }); - const scrimStyles = await page.evaluate(() => { - const scrim = document.querySelector("calcite-modal").shadowRoot.querySelector(".scrim"); - return window.getComputedStyle(scrim).getPropertyValue("--calcite-scrim-background"); - }); - expect(scrimStyles.trim()).toEqual("rgba(0, 0, 0, 0.85)"); - }); - - it("when modal css override set, scrim should adhere to requested color", async () => { - const overrideStyle = "rgba(160, 20, 10, 0.5)"; - const page = await newE2EPage({ - html: ` - - -
The actual content of the modal
- - Back - - Cancel - Save -
- `, - }); - const scrimStyles = await page.evaluate(() => { - const scrim = document.querySelector("calcite-modal").shadowRoot.querySelector(".scrim"); - return window.getComputedStyle(scrim).getPropertyValue("--calcite-scrim-background"); - }); - expect(scrimStyles).toEqual(overrideStyle); - }); - it("correctly reflects the scale of the modal on the close button icon", async () => { const page = await newE2EPage(); await page.setContent(html` `); + await skipAnimations(page); const modal = await page.find("calcite-modal"); modal.setProperty("scale", "s"); await page.waitForChanges(); diff --git a/packages/calcite-components/src/components/popover/popover.e2e.ts b/packages/calcite-components/src/components/popover/popover.e2e.ts index 68a40bf99b6..fe7eeda52df 100644 --- a/packages/calcite-components/src/components/popover/popover.e2e.ts +++ b/packages/calcite-components/src/components/popover/popover.e2e.ts @@ -267,60 +267,60 @@ describe("calcite-popover", () => { it("should honor Enter key interaction", async () => { const page = await newE2EPage(); - await page.setContent( html`content
referenceElement
`, ); - await skipAnimations(page); - await page.waitForChanges(); - const positionContainer = await page.find(`calcite-popover >>> .${CSS.positionContainer}`); const ref = await page.find("#ref"); expect(await positionContainer.isVisible()).toBe(false); + const openEventSpy = await page.spyOnEvent("calcitePopoverOpen"); await ref.focus(); await page.keyboard.press("Enter"); await page.waitForChanges(); + await openEventSpy.next(); expect(await positionContainer.isVisible()).toBe(true); + const closeEventSpy = await page.spyOnEvent("calcitePopoverClose"); await ref.focus(); await page.keyboard.press("Enter"); await page.waitForChanges(); + await closeEventSpy.next(); expect(await positionContainer.isVisible()).toBe(false); }); it("should honor Space key interaction", async () => { const page = await newE2EPage(); - await page.setContent( html`content
referenceElement
`, ); - await skipAnimations(page); - await page.waitForChanges(); - const positionContainer = await page.find(`calcite-popover >>> .${CSS.positionContainer}`); const ref = await page.find("#ref"); expect(await positionContainer.isVisible()).toBe(false); + const openEventSpy = await page.spyOnEvent("calcitePopoverOpen"); await ref.focus(); await page.keyboard.press(" "); await page.waitForChanges(); + await openEventSpy.next(); expect(await positionContainer.isVisible()).toBe(true); + const closeEventSpy = await page.spyOnEvent("calcitePopoverClose"); await ref.focus(); await page.keyboard.press(" "); await page.waitForChanges(); + await closeEventSpy.next(); expect(await positionContainer.isVisible()).toBe(false); }); @@ -660,7 +660,6 @@ describe("calcite-popover", () => { it("should still function when disconnected and reconnected", async () => { const page = await newE2EPage(); - await page.setContent( `content
@@ -672,17 +671,20 @@ describe("calcite-popover", () => { const ref = await page.find("#ref"); expect(await positionContainer.isVisible()).toBe(true); + const closeEventSpy = await page.spyOnEvent("calcitePopoverClose"); await ref.click(); - await page.waitForChanges(); + await closeEventSpy.next(); + expect(await positionContainer.isVisible()).toBe(false); await page.$eval("calcite-popover", (popoverEl: Popover["el"]) => { const transferEl = document.getElementById("transfer"); transferEl.appendChild(popoverEl); }); - await page.waitForChanges(); + const openEventSpy = await page.spyOnEvent("calcitePopoverOpen"); await ref.click(); + await openEventSpy.next(); expect(await positionContainer.isVisible()).toBe(true); }); diff --git a/packages/calcite-components/src/components/sheet/sheet.e2e.ts b/packages/calcite-components/src/components/sheet/sheet.e2e.ts index fc566ab0e94..9f632701a7b 100644 --- a/packages/calcite-components/src/components/sheet/sheet.e2e.ts +++ b/packages/calcite-components/src/components/sheet/sheet.e2e.ts @@ -1,9 +1,9 @@ // @ts-strict-ignore -import { newE2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; -import { describe, expect, it, vi } from "vitest"; +import { E2EElement, E2EPage, newE2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; +import { beforeEach, describe, expect, it, vi } from "vitest"; import { html } from "../../../support/formatting"; import { accessible, defaults, focusable, hidden, openClose, reflects, renders, themed } from "../../tests/commonTests"; -import { GlobalTestProps, newProgrammaticE2EPage, skipAnimations } from "../../tests/utils/puppeteer"; +import { GlobalTestProps, skipAnimations } from "../../tests/utils/puppeteer"; import { resizeStep, resizeShiftStep } from "../../utils/resources"; import { focusTrap } from "../../tests/commonTests/focusTrap"; import { mockConsole } from "../../tests/utils/logging"; @@ -101,17 +101,41 @@ describe("calcite-sheet", () => { }); describe("accessible", () => { - accessible(`Hello everyone!`); - accessible(`

- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore - magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo - consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. - Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -

- tincidunt lobortis - amet porttitor -
`); + accessible(async () => { + const page = await newE2EPage(); + await page.setContent(html`Hello everyone!`); + const openEventSpy = await page.spyOnEvent("calciteSheetOpen"); + const sheet = await page.find("calcite-sheet"); + sheet.setProperty("open", true); + await page.waitForChanges(); + await openEventSpy.next(); + return { page, tag: "calcite-sheet" }; + }); + + accessible(async () => { + const page = await newE2EPage(); + await page.setContent(html` + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et + dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex + ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu + fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt + mollit anim id est laborum. +

+ tincidunt lobortis + amet porttitor +
+
+ `); + const openEventSpy = await page.spyOnEvent("calciteSheetOpen"); + const sheet = await page.find("calcite-sheet"); + sheet.setProperty("open", true); + await page.waitForChanges(); + await openEventSpy.next(); + return { page, tag: "calcite-sheet" }; + }); }); describe("setFocus", () => { @@ -210,113 +234,109 @@ describe("calcite-sheet", () => { expect(style).toEqual("600px"); }); - it("calls the beforeClose method prior to closing via click", async () => { - const page = await newE2EPage(); - const mockCallBack = vi.fn(); - await page.exposeFunction("beforeClose", mockCallBack); - await page.setContent(` - - `); - const sheet = await page.find("calcite-sheet"); - await page.$eval( - "calcite-sheet", - (elm: Sheet["el"]) => - (elm.beforeClose = (window as GlobalTestProps<{ beforeClose: Sheet["el"]["beforeClose"] }>).beforeClose), - ); - await page.waitForChanges(); - expect(await sheet.getProperty("opened")).toBe(true); - const scrim = await page.find(`calcite-sheet >>> calcite-scrim`); - await scrim.click(); - await page.waitForChanges(); - expect(mockCallBack).toHaveBeenCalledTimes(1); - expect(await sheet.getProperty("opened")).toBe(false); - }); + describe("beforeClose", () => { + let page: E2EPage; + let sheet: E2EElement; - it("calls the beforeClose method prior to closing via escape", async () => { - const page = await newE2EPage(); - const mockCallBack = vi.fn(); - await page.exposeFunction("beforeClose", mockCallBack); - await page.setContent(` - - `); - const sheet = await page.find("calcite-sheet"); - await page.$eval( - "calcite-sheet", - (elm: Sheet["el"]) => - (elm.beforeClose = (window as GlobalTestProps<{ beforeClose: Sheet["el"]["beforeClose"] }>).beforeClose), - ); - await skipAnimations(page); - await page.waitForEvent("calciteSheetOpen"); - expect(await sheet.getProperty("opened")).toBe(true); + beforeEach(async () => { + page = await newE2EPage(); + await page.setContent(html``); + await skipAnimations(page); + sheet = await page.find("calcite-sheet"); + const openEventSpy = await page.spyOnEvent("calciteSheetOpen"); + sheet.setProperty("open", true); + await page.waitForChanges(); + await openEventSpy.next(); + }); - await page.keyboard.press("Escape"); - await page.waitForChanges(); + it("calls the beforeClose method prior to closing via click", async () => { + const mockCallBack = vi.fn(); + await page.exposeFunction("beforeClose", mockCallBack); + await page.$eval( + "calcite-sheet", + (el: Sheet["el"]) => + (el.beforeClose = (window as GlobalTestProps<{ beforeClose: Sheet["el"]["beforeClose"] }>).beforeClose), + ); + await page.waitForChanges(); - expect(mockCallBack).toHaveBeenCalledTimes(1); - expect(await sheet.getProperty("opened")).toBe(false); - }); + expect(await sheet.getProperty("opened")).toBe(true); - it("calls the beforeClose method prior to closing via attribute", async () => { - const page = await newE2EPage(); - const mockCallBack = vi.fn(); - await page.exposeFunction("beforeClose", mockCallBack); - await page.setContent(` - - `); - const sheet = await page.find("calcite-sheet"); - await page.$eval( - "calcite-sheet", - (elm: Sheet["el"]) => - (elm.beforeClose = (window as GlobalTestProps<{ beforeClose: Sheet["el"]["beforeClose"] }>).beforeClose), - ); - await page.waitForChanges(); - sheet.setProperty("open", true); - await page.waitForChanges(); - expect(await sheet.getProperty("opened")).toBe(true); - sheet.removeAttribute("open"); - await page.waitForChanges(); - expect(mockCallBack).toHaveBeenCalledTimes(1); - expect(await sheet.getProperty("opened")).toBe(false); - }); + const scrim = await page.find(`calcite-sheet >>> calcite-scrim`); + await scrim.click(); + await page.waitForChanges(); - it("should handle rejected 'beforeClose' promise'", async () => { - const page = await newE2EPage(); + expect(mockCallBack).toHaveBeenCalledTimes(1); + expect(await sheet.getProperty("opened")).toBe(false); + }); - const mockCallBack = vi.fn().mockReturnValue(() => Promise.reject()); - await page.exposeFunction("beforeClose", mockCallBack); + it("calls the beforeClose method prior to closing via escape", async () => { + const mockCallBack = vi.fn(); + await page.exposeFunction("beforeClose", mockCallBack); + await page.$eval( + "calcite-sheet", + (el: Sheet["el"]) => + (el.beforeClose = (window as GlobalTestProps<{ beforeClose: Sheet["el"]["beforeClose"] }>).beforeClose), + ); + await page.waitForChanges(); - await page.setContent(``); + expect(await sheet.getProperty("opened")).toBe(true); - await page.$eval( - "calcite-sheet", - (elm: Sheet["el"]) => (elm.beforeClose = (window as typeof window & Pick).beforeClose), - ); + await page.keyboard.press("Escape"); + await page.waitForChanges(); + expect(mockCallBack).toHaveBeenCalledTimes(1); + expect(await sheet.getProperty("opened")).toBe(false); + }); - const sheet = await page.find("calcite-sheet"); - sheet.setProperty("open", false); - await page.waitForChanges(); + it("calls the beforeClose method prior to closing via attribute", async () => { + const mockCallBack = vi.fn(); + await page.exposeFunction("beforeClose", mockCallBack); + await page.$eval( + "calcite-sheet", + (el: Sheet["el"]) => + (el.beforeClose = (window as GlobalTestProps<{ beforeClose: Sheet["el"]["beforeClose"] }>).beforeClose), + ); + await page.waitForChanges(); - expect(mockCallBack).toHaveBeenCalledTimes(1); - }); + expect(await sheet.getProperty("opened")).toBe(true); - it("should remain open with rejected 'beforeClose' promise'", async () => { - const page = await newE2EPage(); + sheet.removeAttribute("open"); + await page.waitForChanges(); - await page.exposeFunction("beforeClose", () => Promise.reject()); - await page.setContent(``); + expect(mockCallBack).toHaveBeenCalledTimes(1); + expect(await sheet.getProperty("opened")).toBe(false); + }); - await page.$eval( - "calcite-sheet", - (elm: Sheet["el"]) => (elm.beforeClose = (window as typeof window & Pick).beforeClose), - ); + it("should handle rejected 'beforeClose' promise'", async () => { + const mockCallBack = vi.fn().mockReturnValue(() => Promise.reject()); + await page.exposeFunction("beforeClose", mockCallBack); + await page.$eval( + "calcite-sheet", + (elm: Sheet["el"]) => + (elm.beforeClose = (window as typeof window & Pick).beforeClose), + ); + await page.waitForChanges(); - const sheet = await page.find("calcite-sheet"); - sheet.setProperty("open", false); - await page.waitForChanges(); + sheet.setProperty("open", false); + await page.waitForChanges(); - expect(await sheet.getProperty("open")).toBe(true); - expect(await sheet.getProperty("opened")).toBe(true); - expect(sheet.getAttribute("open")).toBe(""); // Makes sure attribute is added back + expect(mockCallBack).toHaveBeenCalledTimes(1); + }); + + it("should remain open with rejected 'beforeClose' promise'", async () => { + await page.exposeFunction("beforeClose", () => Promise.reject()); + await page.$eval( + "calcite-sheet", + (elm: Sheet["el"]) => + (elm.beforeClose = (window as typeof window & Pick).beforeClose), + ); + + sheet.setProperty("open", false); + await page.waitForChanges(); + + expect(await sheet.getProperty("open")).toBe(true); + expect(await sheet.getProperty("opened")).toBe(true); + expect(sheet.getAttribute("open")).toBe(""); // Makes sure attribute is added back + }); }); it("has correct aria role/attribute", async () => { @@ -329,18 +349,29 @@ describe("calcite-sheet", () => { it("closes and allows re-opening when Escape key is pressed", async () => { const page = await newE2EPage(); - await page.setContent(``); + await page.setContent(``); await skipAnimations(page); const sheet = await page.find("calcite-sheet"); + + const openEventSpy = await page.spyOnEvent("calciteSheetOpen"); sheet.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); + expect(await sheet.isVisible()).toBe(true); + + const closeEventSpy = await page.spyOnEvent("calciteSheetClose"); await page.keyboard.press("Escape"); await page.waitForChanges(); + await closeEventSpy.next(); + expect(await sheet.isVisible()).toBe(false); expect(await sheet.getProperty("open")).toBe(false); + sheet.setProperty("open", true); await page.waitForChanges(); + await openEventSpy.next(); + expect(await sheet.isVisible()).toBe(true); }); @@ -433,208 +464,6 @@ describe("calcite-sheet", () => { expect(documentClass).toEqual(false); }); - describe("opening and closing behavior", () => { - it("opens and closes", async () => { - const page = await newE2EPage(); - await page.setContent(html``); - const sheet = await page.find("calcite-sheet"); - - type SheetEventOrderWindow = GlobalTestProps<{ events: string[] }>; - - await page.$eval("calcite-sheet", (sheet: Sheet["el"]) => { - const receivedEvents: string[] = []; - (window as SheetEventOrderWindow).events = receivedEvents; - - ["calciteSheetBeforeOpen", "calciteSheetOpen", "calciteSheetBeforeClose", "calciteSheetClose"].forEach( - (eventType) => { - sheet.addEventListener(eventType, (event) => receivedEvents.push(event.type)); - }, - ); - }); - - const beforeOpenSpy = await sheet.spyOnEvent("calciteSheetBeforeOpen"); - const openSpy = await sheet.spyOnEvent("calciteSheetOpen"); - const beforeCloseSpy = await sheet.spyOnEvent("calciteSheetBeforeClose"); - const closeSpy = await sheet.spyOnEvent("calciteSheetClose"); - - expect(beforeOpenSpy).toHaveReceivedEventTimes(0); - expect(openSpy).toHaveReceivedEventTimes(0); - expect(beforeCloseSpy).toHaveReceivedEventTimes(0); - expect(closeSpy).toHaveReceivedEventTimes(0); - - expect(await sheet.isVisible()).toBe(false); - - const sheetBeforeOpen = page.waitForEvent("calciteSheetBeforeOpen"); - const sheetOpen = page.waitForEvent("calciteSheetOpen"); - sheet.setProperty("open", true); - await page.waitForChanges(); - - await sheetBeforeOpen; - await sheetOpen; - - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - expect(beforeCloseSpy).toHaveReceivedEventTimes(0); - expect(closeSpy).toHaveReceivedEventTimes(0); - - expect(await sheet.isVisible()).toBe(true); - - const sheetBeforeClose = page.waitForEvent("calciteSheetBeforeClose"); - const sheetClose = page.waitForEvent("calciteSheetClose"); - sheet.setProperty("open", false); - await page.waitForChanges(); - - await sheetBeforeClose; - await sheetClose; - - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - expect(beforeCloseSpy).toHaveReceivedEventTimes(1); - expect(closeSpy).toHaveReceivedEventTimes(1); - - expect(await sheet.isVisible()).toBe(false); - - expect(await page.evaluate(() => (window as SheetEventOrderWindow).events)).toEqual([ - "calciteSheetBeforeOpen", - "calciteSheetOpen", - "calciteSheetBeforeClose", - "calciteSheetClose", - ]); - }); - - it("emits when closing on click", async () => { - const page = await newE2EPage(); - await page.setContent(html``); - const sheet = await page.find("calcite-sheet"); - - const beforeOpenSpy = await sheet.spyOnEvent("calciteSheetBeforeOpen"); - const openSpy = await sheet.spyOnEvent("calciteSheetOpen"); - const beforeCloseSpy = await sheet.spyOnEvent("calciteSheetBeforeClose"); - const closeSpy = await sheet.spyOnEvent("calciteSheetClose"); - - expect(beforeOpenSpy).toHaveReceivedEventTimes(0); - expect(openSpy).toHaveReceivedEventTimes(0); - expect(beforeCloseSpy).toHaveReceivedEventTimes(0); - expect(closeSpy).toHaveReceivedEventTimes(0); - - expect(await sheet.isVisible()).toBe(false); - - const sheetBeforeOpen = page.waitForEvent("calciteSheetBeforeOpen"); - const sheetOpen = page.waitForEvent("calciteSheetOpen"); - sheet.setProperty("open", true); - await page.waitForChanges(); - - await sheetBeforeOpen; - await sheetOpen; - - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - expect(beforeCloseSpy).toHaveReceivedEventTimes(0); - expect(closeSpy).toHaveReceivedEventTimes(0); - - expect(await sheet.isVisible()).toBe(true); - - const sheetBeforeClose = page.waitForEvent("calciteSheetBeforeClose"); - const sheetClose = page.waitForEvent("calciteSheetClose"); - const scrim = await page.find(`calcite-sheet >>> .${CSS.scrim}`); - await scrim.click(); - await page.waitForChanges(); - - await sheetBeforeClose; - await sheetClose; - - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - expect(beforeCloseSpy).toHaveReceivedEventTimes(1); - expect(closeSpy).toHaveReceivedEventTimes(1); - - expect(await sheet.isVisible()).toBe(false); - }); - - it("emits when set to open on initial render", async () => { - const page = await newProgrammaticE2EPage(); - - const beforeOpenSpy = await page.spyOnEvent("calciteSheetBeforeOpen"); - const openSpy = await page.spyOnEvent("calciteSheetOpen"); - - const waitForBeforeOpenEvent = page.waitForEvent("calciteSheetBeforeOpen"); - const waitForOpenEvent = page.waitForEvent("calciteSheetOpen"); - - await page.evaluate((): void => { - const sheet = document.createElement("calcite-sheet"); - sheet.open = true; - document.body.append(sheet); - }); - - await page.waitForChanges(); - await waitForBeforeOpenEvent; - await waitForOpenEvent; - - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - }); - - it("emits when set to open on initial render and duration is 0", async () => { - const page = await newProgrammaticE2EPage(); - await skipAnimations(page); - - const beforeOpenSpy = await page.spyOnEvent("calciteSheetBeforeOpen"); - const openSpy = await page.spyOnEvent("calciteSheetOpen"); - - const waitForOpenEvent = page.waitForEvent("calciteSheetOpen"); - const waitForBeforeOpenEvent = page.waitForEvent("calciteSheetBeforeOpen"); - - await page.evaluate((): void => { - const sheet = document.createElement("calcite-sheet"); - sheet.open = true; - document.body.append(sheet); - }); - - await page.waitForChanges(); - await waitForBeforeOpenEvent; - await waitForOpenEvent; - - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - }); - - it("emits when duration is set to 0", async () => { - const page = await newProgrammaticE2EPage(); - await skipAnimations(page); - - const beforeOpenSpy = await page.spyOnEvent("calciteSheetBeforeOpen"); - const openSpy = await page.spyOnEvent("calciteSheetOpen"); - - const beforeCloseSpy = await page.spyOnEvent("calciteSheetBeforeClose"); - const closeSpy = await page.spyOnEvent("calciteSheetClose"); - - await page.evaluate((): void => { - const sheet = document.createElement("calcite-sheet"); - sheet.open = true; - document.body.append(sheet); - }); - - await page.waitForChanges(); - await beforeOpenSpy; - await openSpy; - - expect(beforeOpenSpy).toHaveReceivedEventTimes(1); - expect(openSpy).toHaveReceivedEventTimes(1); - - await page.evaluate(() => { - const sheet = document.querySelector("calcite-sheet"); - sheet.open = false; - }); - - await page.waitForChanges(); - await beforeCloseSpy; - await closeSpy; - - expect(beforeCloseSpy).toHaveReceivedEventTimes(1); - expect(closeSpy).toHaveReceivedEventTimes(1); - }); - }); - describe("keyboard resize", () => { it("should resize properly via arrow keys", async () => { const maxSize = 600; diff --git a/packages/calcite-components/src/components/shell/shell.e2e.ts b/packages/calcite-components/src/components/shell/shell.e2e.ts index c9ce30431a7..51c87fdaaad 100644 --- a/packages/calcite-components/src/components/shell/shell.e2e.ts +++ b/packages/calcite-components/src/components/shell/shell.e2e.ts @@ -2,6 +2,7 @@ import { newE2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; import { describe, expect, it } from "vitest"; import { accessible, hidden, renders, slots, themed } from "../../tests/commonTests"; import { html } from "../../../support/formatting"; +import { getFocusedElementProp } from "../../tests/utils/puppeteer"; import { mockConsole } from "../../tests/utils/logging"; import { CSS, SLOTS } from "./resources"; @@ -164,10 +165,13 @@ describe("calcite-shell", () => { `, ); const block = await page.find("calcite-block"); - block.click(); - await page.waitForChanges(); + + const openEventSpy = await block.spyOnEvent("calciteBlockOpen"); + await block.click(); + await openEventSpy.next(); + expect(await block.getProperty("expanded")).toBe(true); - expect(await page.evaluate(() => document.activeElement.id)).toEqual(block.id); + expect(await getFocusedElementProp(page, "id")).toEqual(block.id); }); it("modal dialog embedded in shell slot does not prevent interaction with page content outside slot", async () => { @@ -188,10 +192,12 @@ describe("calcite-shell", () => { ); const block = await page.find("calcite-block"); - block.click(); - await page.waitForChanges(); + const openEventSpy = await block.spyOnEvent("calciteBlockOpen"); + await block.click(); + await openEventSpy.next(); + expect(await block.getProperty("expanded")).toBe(true); - expect(await page.evaluate(() => document.activeElement.id)).toEqual(block.id); + expect(await getFocusedElementProp(page, "id")).toEqual(block.id); }); it("deprecated modal embedded in shell slot does not prevent interaction with page content outside slot", async () => { @@ -213,10 +219,13 @@ describe("calcite-shell", () => { `, ); const block = await page.find("calcite-block"); - block.click(); - await page.waitForChanges(); + + const openEventSpy = await block.spyOnEvent("calciteBlockOpen"); + await block.click(); + await openEventSpy.next(); + expect(await block.getProperty("expanded")).toBe(true); - expect(await page.evaluate(() => document.activeElement.id)).toEqual(block.id); + expect(await getFocusedElementProp(page, "id")).toEqual(block.id); }); }); diff --git a/packages/calcite-components/src/components/sort-handle/sort-handle.e2e.ts b/packages/calcite-components/src/components/sort-handle/sort-handle.e2e.ts index 99334d1187c..7927dd96c24 100644 --- a/packages/calcite-components/src/components/sort-handle/sort-handle.e2e.ts +++ b/packages/calcite-components/src/components/sort-handle/sort-handle.e2e.ts @@ -69,8 +69,10 @@ describe("calcite-sort-handle", () => { const action = await page.find(`calcite-sort-handle >>> .${CSS.handle}`); await action.callMethod("setFocus"); + const openEventSpy = await page.spyOnEvent("calciteSortHandleOpen"); await page.keyboard.press("ArrowDown"); await page.waitForChanges(); + await openEventSpy.next(); expect(await sortHandle.getProperty("open")).toBe(true); await page.keyboard.press("Enter"); @@ -99,8 +101,10 @@ describe("calcite-sort-handle", () => { const action = await page.find(`calcite-sort-handle >>> .${CSS.handle}`); await action.callMethod("setFocus"); + const openEventSpy = await page.spyOnEvent("calciteSortHandleOpen"); await page.keyboard.press("ArrowUp"); await page.waitForChanges(); + await openEventSpy.next(); expect(await sortHandle.getProperty("open")).toBe(true); await page.keyboard.press(" "); diff --git a/packages/calcite-components/src/components/split-button/split-button.e2e.ts b/packages/calcite-components/src/components/split-button/split-button.e2e.ts index 6a819f33749..3d62381fc3b 100644 --- a/packages/calcite-components/src/components/split-button/split-button.e2e.ts +++ b/packages/calcite-components/src/components/split-button/split-button.e2e.ts @@ -277,9 +277,9 @@ describe("calcite-split-button", () => { `); const positionContainer = await page.find(`calcite-split-button >>> calcite-dropdown >>> .${DropdownCSS.wrapper}`); const secondary = await page.find(`calcite-split-button >>> calcite-button[split-child="secondary"]`); - const dropdownOpenEvent = page.waitForEvent("calciteDropdownOpen"); + const dropdownOpenEventSpy = await page.spyOnEvent("calciteDropdownOpen"); await secondary.click(); - await dropdownOpenEvent; + await dropdownOpenEventSpy.next(); expect(await positionContainer.isVisible()).toBe(true); expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-1"); await page.keyboard.press("ArrowDown"); @@ -288,9 +288,10 @@ describe("calcite-split-button", () => { await page.keyboard.press("ArrowDown"); await page.waitForChanges(); expect(await page.evaluate(() => document.activeElement.id)).toEqual("item-3"); - const dropdownCloseEvent = page.waitForEvent("calciteDropdownClose"); + const dropdownCloseEventSpy = await page.spyOnEvent("calciteDropdownClose"); await page.keyboard.press("Enter"); - await dropdownCloseEvent; + await page.waitForChanges(); + await dropdownCloseEventSpy.next(); expect(await positionContainer.isVisible()).toBe(false); }); diff --git a/packages/calcite-components/src/components/tab-nav/tab-nav.e2e.ts b/packages/calcite-components/src/components/tab-nav/tab-nav.e2e.ts index e6ccb8f660c..37bf11c1dca 100644 --- a/packages/calcite-components/src/components/tab-nav/tab-nav.e2e.ts +++ b/packages/calcite-components/src/components/tab-nav/tab-nav.e2e.ts @@ -185,31 +185,24 @@ describe("calcite-tab-nav", () => { it("scrolling tabs via buttons", async () => { await assertScrollButtonVisibility(false, true); - let scrollEnd = scrollContainer.waitForEvent("scrollend"); + const scrollEndEventSpy = await scrollContainer.spyOnEvent("scrollend"); await scrollForwardButton.click(); - await page.waitForChanges(); - await scrollEnd; + await scrollEndEventSpy.next(); await assertScrollButtonVisibility(true, true); - scrollEnd = scrollContainer.waitForEvent("scrollend"); await scrollForwardButton.click(); - await page.waitForChanges(); - await scrollEnd; + await scrollEndEventSpy.next(); await assertScrollButtonVisibility(true, false); - scrollEnd = scrollContainer.waitForEvent("scrollend"); await scrollBackButton.click(); - await page.waitForChanges(); - await scrollEnd; + await scrollEndEventSpy.next(); await assertScrollButtonVisibility(true, true); - scrollEnd = scrollContainer.waitForEvent("scrollend"); await scrollBackButton.click(); - await page.waitForChanges(); - await scrollEnd; + await scrollEndEventSpy.next(); await assertScrollButtonVisibility(false, true); }); @@ -241,33 +234,34 @@ describe("calcite-tab-nav", () => { }); it("scrolls into view clipped start or end tab-title when selected", async () => { + const scrollEndEventSpy = await scrollContainer.spyOnEvent("scrollend"); const tabNavBounds = await getElementRect(page, "calcite-tab-nav"); await page.mouse.move(tabNavBounds.x + tabNavBounds.width / 2, tabNavBounds.y + tabNavBounds.height / 2); await page.waitForChanges(); await page.mouse.wheel({ deltaY: 1 }); await page.waitForChanges(); + await scrollEndEventSpy.next(); await assertScrollButtonVisibility(true, true); - let scrollEnd = scrollContainer.waitForEvent("scrollend"); const firstTab = await page.find("calcite-tab-title:first-child"); await firstTab.callMethod("click"); // we call method to avoid having E2E click element in the middle, which would hit the scroll button await page.waitForChanges(); - await scrollEnd; + await scrollEndEventSpy.next(); await assertScrollButtonVisibility(false, true); await page.mouse.wheel({ deltaY: 180 }); await page.waitForChanges(); + await scrollEndEventSpy.next(); await assertScrollButtonVisibility(true, true); - scrollEnd = scrollContainer.waitForEvent("scrollend"); const lastTab = await page.find("calcite-tab-title:last-child"); await lastTab.callMethod("click"); // we call method to avoid having E2E click element in the middle, which would hit the scroll button await page.waitForChanges(); - await scrollEnd; + await scrollEndEventSpy.next(); await assertScrollButtonVisibility(true, false); }); diff --git a/packages/calcite-components/src/components/tabs/tabs.e2e.ts b/packages/calcite-components/src/components/tabs/tabs.e2e.ts index f601753a222..c49891e2022 100644 --- a/packages/calcite-components/src/components/tabs/tabs.e2e.ts +++ b/packages/calcite-components/src/components/tabs/tabs.e2e.ts @@ -302,9 +302,10 @@ describe("calcite-tabs", () => { ), ); - const tabChange = page.waitForEvent("calciteTabChange"); + const tabChangeEventSpy = await page.spyOnEvent("calciteTabChange"); await page.click("calcite-tab-title"); - await tabChange; + await page.waitForChanges(); + await tabChangeEventSpy.next(); const selectedTitleOnEmit = await page.evaluate(() => (window as TestWindow).selectedTitleTab); diff --git a/packages/calcite-components/src/components/text-area/text-area.e2e.ts b/packages/calcite-components/src/components/text-area/text-area.e2e.ts index 97d3cb1862f..4c1a498cd35 100644 --- a/packages/calcite-components/src/components/text-area/text-area.e2e.ts +++ b/packages/calcite-components/src/components/text-area/text-area.e2e.ts @@ -351,15 +351,15 @@ describe("calcite-text-area", () => { }); const element = await page.find("calcite-text-area"); const textAreaRect = await getElementRect(page, "calcite-text-area", "textarea"); - const inputEvent = page.waitForEvent("calciteTextAreaInput"); + const inputEventSpy = await page.spyOnEvent("calciteTextAreaInput"); await element.callMethod("setFocus"); await page.keyboard.type("a"); await page.waitForChanges(); - await inputEvent; - const inputEvent2 = page.waitForEvent("calciteTextAreaInput"); + await inputEventSpy.next(); + const inputEventSpy2 = await page.spyOnEvent("calciteTextAreaInput"); await page.waitForChanges(); await page.keyboard.press("Backspace"); - await inputEvent2; + await inputEventSpy2.next(); expect(await element.getProperty("status")).toBe("invalid"); const textAreaInvalidRect = await getElementRect(page, "calcite-text-area", "textarea"); diff --git a/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts b/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts index d99a33ef615..e0a778c596b 100644 --- a/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts +++ b/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts @@ -325,27 +325,22 @@ describe("calcite-tooltip", () => { it("should not open when hover event is prevented", async () => { const page = await newE2EPage(); - await page.setContent( `content
referenceElement
`, ); - - await page.waitForChanges(); - + await skipAnimations(page); const positionContainer = await page.find(`calcite-tooltip >>> .${CSS.positionContainer}`); - - expect(await positionContainer.isVisible()).toBe(false); - + const ref = await page.find("#ref"); await page.$eval("#ref", (ref) => { ref.addEventListener("pointermove", (event) => { event.preventDefault(); }); }); - const ref = await page.find("#ref"); + expect(await positionContainer.isVisible()).toBe(false); await ref.hover(); - + await page.waitForChanges(); await page.waitForTimeout(TOOLTIP_OPEN_DELAY_MS); expect(await positionContainer.isVisible()).toBe(false); @@ -360,13 +355,13 @@ describe("calcite-tooltip", () => { `); await skipAnimations(page); - await page.waitForChanges(); - const positionContainer = await page.find(`calcite-tooltip >>> .${CSS.positionContainer}`); - const ref = await page.find("#ref"); + await ref.hover(); + await page.waitForChanges(); await page.waitForTimeout(TOOLTIP_OPEN_DELAY_MS); + expect(await positionContainer.isVisible()).toBe(true); await page.$eval("#button-container", (buttonContainer) => { @@ -376,6 +371,7 @@ describe("calcite-tooltip", () => { }); await ref.hover(); + await page.waitForChanges(); await page.waitForTimeout(TOOLTIP_CLOSE_DELAY_MS); expect(await positionContainer.isVisible()).toBe(false); }); @@ -871,26 +867,24 @@ describe("calcite-tooltip", () => { it("emits via prop", async () => { await assertEventEmitting({ openTooltip: async (page) => { - const tooltipBeforeOpenEvent = page.waitForEvent("calciteTooltipBeforeOpen"); - const tooltipOpenEvent = page.waitForEvent("calciteTooltipOpen"); + const beforeOpenSpy = await page.spyOnEvent("calciteTooltipBeforeOpen"); + const openSpy = await page.spyOnEvent("calciteTooltipOpen"); const tooltip = await page.find("calcite-tooltip"); tooltip.setProperty("open", true); await page.waitForChanges(); - - await tooltipBeforeOpenEvent; - await tooltipOpenEvent; + await beforeOpenSpy.next(); + await openSpy.next(); }, closeTooltip: async (page) => { - const tooltipBeforeCloseEvent = page.waitForEvent("calciteTooltipBeforeClose"); - const tooltipCloseEvent = page.waitForEvent("calciteTooltipClose"); + const beforeCloseSpy = await page.spyOnEvent("calciteTooltipBeforeClose"); + const closeSpy = await page.spyOnEvent("calciteTooltipClose"); const tooltip = await page.find("calcite-tooltip"); tooltip.setProperty("open", false); await page.waitForChanges(); - - await tooltipBeforeCloseEvent; - await tooltipCloseEvent; + await beforeCloseSpy.next(); + await closeSpy.next(); }, }); }); @@ -908,7 +902,6 @@ describe("calcite-tooltip", () => { await page.mouse.move(refElementX, refElementY, moveOptions); await page.mouse.move(refElementX + xMoveOffset, refElementY, moveOptions); await page.waitForChanges(); - await page.waitForTimeout(totalDelayFromMoveSteps); }, closeTooltip: async (page: E2EPage) => { @@ -918,7 +911,6 @@ describe("calcite-tooltip", () => { await page.mouse.move(refElementX, refElementY, moveOptions); await page.mouse.move(0, 0, moveOptions); await page.waitForChanges(); - await page.waitForTimeout(totalDelayFromMoveSteps); }, }); @@ -945,33 +937,36 @@ describe("calcite-tooltip", () => { await page.setContent( `content`, ); + await skipAnimations(page); const tooltip = await page.find("calcite-tooltip"); - const beforeOpenEvent = await tooltip.spyOnEvent("calciteTooltipBeforeOpen"); - const openEvent = await tooltip.spyOnEvent("calciteTooltipOpen"); - const beforeCloseEvent = await tooltip.spyOnEvent("calciteTooltipBeforeClose"); - const closeEvent = await tooltip.spyOnEvent("calciteTooltipClose"); + const beforeOpenEventSpy = await tooltip.spyOnEvent("calciteTooltipBeforeOpen"); + const openEventSpy = await tooltip.spyOnEvent("calciteTooltipOpen"); + const beforeCloseEventSpy = await tooltip.spyOnEvent("calciteTooltipBeforeClose"); + const closeEventSpy = await tooltip.spyOnEvent("calciteTooltipClose"); - expect(beforeOpenEvent).toHaveReceivedEventTimes(0); - expect(openEvent).toHaveReceivedEventTimes(0); - expect(beforeCloseEvent).toHaveReceivedEventTimes(0); - expect(closeEvent).toHaveReceivedEventTimes(0); + expect(beforeOpenEventSpy).toHaveReceivedEventTimes(0); + expect(openEventSpy).toHaveReceivedEventTimes(0); + expect(beforeCloseEventSpy).toHaveReceivedEventTimes(0); + expect(closeEventSpy).toHaveReceivedEventTimes(0); await params.openTooltip(page); await page.waitForChanges(); + await openEventSpy.next(); - expect(beforeOpenEvent).toHaveReceivedEventTimes(1); - expect(openEvent).toHaveReceivedEventTimes(1); - expect(beforeCloseEvent).toHaveReceivedEventTimes(0); - expect(closeEvent).toHaveReceivedEventTimes(0); + expect(beforeOpenEventSpy).toHaveReceivedEventTimes(1); + expect(openEventSpy).toHaveReceivedEventTimes(1); + expect(beforeCloseEventSpy).toHaveReceivedEventTimes(0); + expect(closeEventSpy).toHaveReceivedEventTimes(0); await params.closeTooltip(page); await page.waitForChanges(); + await closeEventSpy.next(); - expect(beforeOpenEvent).toHaveReceivedEventTimes(1); - expect(openEvent).toHaveReceivedEventTimes(1); - expect(beforeCloseEvent).toHaveReceivedEventTimes(1); - expect(closeEvent).toHaveReceivedEventTimes(1); + expect(beforeOpenEventSpy).toHaveReceivedEventTimes(1); + expect(openEventSpy).toHaveReceivedEventTimes(1); + expect(beforeCloseEventSpy).toHaveReceivedEventTimes(1); + expect(closeEventSpy).toHaveReceivedEventTimes(1); } it("when open, it emits close events if no longer rendered", async () => { @@ -1000,6 +995,7 @@ describe("calcite-tooltip", () => { `); + await skipAnimations(page); const beforeCloseEvent = await page.spyOnEvent("calciteTooltipBeforeClose"); const closeEvent = await page.spyOnEvent("calciteTooltipClose"); diff --git a/packages/calcite-components/src/tests/commonTests/accessible.ts b/packages/calcite-components/src/tests/commonTests/accessible.ts index 47a16ddaa28..421c709786c 100644 --- a/packages/calcite-components/src/tests/commonTests/accessible.ts +++ b/packages/calcite-components/src/tests/commonTests/accessible.ts @@ -1,7 +1,7 @@ import axe from "axe-core"; import { toHaveNoViolations } from "jest-axe"; import { expect, it } from "vitest"; -import { GlobalTestProps } from "../utils/puppeteer"; +import { GlobalTestProps, skipAnimations } from "../utils/puppeteer"; import { getTagAndPage } from "./utils"; import { ComponentTestSetup, ComponentTag } from "./interfaces"; @@ -24,6 +24,7 @@ export function accessible(componentTestSetup: ComponentTestSetup): void { it("is accessible", async () => { const { page, tag } = await getTagAndPage(componentTestSetup); + await skipAnimations(page); await page.addScriptTag({ path: require.resolve("axe-core") }); await page.waitForFunction(() => (window as AxeOwningWindow).axe); diff --git a/packages/calcite-components/src/tests/commonTests/disabled.ts b/packages/calcite-components/src/tests/commonTests/disabled.ts index 019769b9496..74920db4ead 100644 --- a/packages/calcite-components/src/tests/commonTests/disabled.ts +++ b/packages/calcite-components/src/tests/commonTests/disabled.ts @@ -2,7 +2,7 @@ import { SetFieldType } from "type-fest"; import { E2EPage, E2EElement, EventSpy } from "@arcgis/lumina-compiler/puppeteerTesting"; import { expect, it } from "vitest"; -import { IntrinsicElementsWithProp, skipAnimations } from "../utils/puppeteer"; +import { IntrinsicElementsWithProp, skipAnimations, waitForAnimationFrame } from "../utils/puppeteer"; import { getTagAndPage } from "./utils"; import { ComponentTestSetup, DisabledOptions, FocusTarget, TabAndClickFocusTargets } from "./interfaces"; @@ -185,6 +185,10 @@ export function disabled(componentTestSetup: ComponentTestSetup, options?: Disab await page.mouse.click(shadowFocusableCenterX, shadowFocusableCenterY); await page.waitForChanges(); + // wait 2 frames to ensure focus has been applied and browser has flushed layout + await waitForAnimationFrame(page); + await waitForAnimationFrame(page); + await expectToBeFocused(page, effectiveFocusTarget.click.pointer, "click"); await resetFocusOrder(); diff --git a/packages/calcite-components/src/tests/commonTests/focusTrap.ts b/packages/calcite-components/src/tests/commonTests/focusTrap.ts index 8ba3202d6b7..621e0a410e3 100644 --- a/packages/calcite-components/src/tests/commonTests/focusTrap.ts +++ b/packages/calcite-components/src/tests/commonTests/focusTrap.ts @@ -1,4 +1,4 @@ -import { E2EPage, E2EElement } from "@arcgis/lumina-compiler/puppeteerTesting"; +import { E2EPage, E2EElement, EventSpy } from "@arcgis/lumina-compiler/puppeteerTesting"; import { beforeEach, describe, expect, it } from "vitest"; import { camelCase, pascalCase } from "change-case"; import { isElementFocused, skipAnimations } from "../utils/puppeteer"; @@ -40,12 +40,12 @@ export function focusTrap(componentTestSetup: ComponentTestSetup, options: Focus let element: E2EElement; let focusTargetSelector: string; - let openEvent: ReturnType; + let openEventSpy: EventSpy; async function toggleComponent(page: E2EPage, element: E2EElement, options: FocusTrapOptions): Promise { element.setProperty(options.toggleProp, true); await page.waitForChanges(); - await openEvent; + await openEventSpy.next(); await page.waitForChanges(); } @@ -54,7 +54,7 @@ export function focusTrap(componentTestSetup: ComponentTestSetup, options: Focus await skipAnimations(page); element = await page.find(tag); const openEventName = `${camelCase(`${tag}${pascalCase(options.toggleProp)}`)}`; - openEvent = page.waitForEvent(openEventName); + openEventSpy = await page.spyOnEvent(openEventName); focusTargetSelector = options.focusTargetSelector || tag; }); diff --git a/packages/calcite-components/src/tests/commonTests/openClose.ts b/packages/calcite-components/src/tests/commonTests/openClose.ts index 3ccb9745e20..825443f2a23 100644 --- a/packages/calcite-components/src/tests/commonTests/openClose.ts +++ b/packages/calcite-components/src/tests/commonTests/openClose.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { E2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; +import { E2EPage, EventSpy } from "@arcgis/lumina-compiler/puppeteerTesting"; import { expect, it } from "vitest"; import { GlobalTestProps, newProgrammaticE2EPage, skipAnimations, toElementHandle } from "../utils/puppeteer"; import { getBeforeContent, getTagAndPage, noopBeforeContent } from "./utils"; @@ -160,22 +160,15 @@ async function testOpenCloseEvents({ }; const eventSequence = getEventSequence(tag); - const [beforeOpenEvent, openEvent, beforeCloseEvent, closeEvent] = eventSequence.map((event) => { - return page.waitForEvent(event).then((spy) => { - timestamps[toOpenCloseName(event)] = Date.now(); - return spy; - }); - }); - - const [beforeOpenSpy, openSpy, beforeCloseSpy, closeSpy] = await Promise.all( + const [beforeOpenEventSpy, openEventSpy, beforeCloseEventSpy, closeEventSpy] = await Promise.all( eventSequence.map(async (event) => await page.spyOnEvent(event)), ); function assertEventSequence(expectedTimesPerEvent: [number, number, number, number]): void { - expect(beforeOpenSpy).toHaveReceivedEventTimes(expectedTimesPerEvent[0]); - expect(openSpy).toHaveReceivedEventTimes(expectedTimesPerEvent[1]); - expect(beforeCloseSpy).toHaveReceivedEventTimes(expectedTimesPerEvent[2]); - expect(closeSpy).toHaveReceivedEventTimes(expectedTimesPerEvent[3]); + expect(beforeOpenEventSpy).toHaveReceivedEventTimes(expectedTimesPerEvent[0]); + expect(openEventSpy).toHaveReceivedEventTimes(expectedTimesPerEvent[1]); + expect(beforeCloseEventSpy).toHaveReceivedEventTimes(expectedTimesPerEvent[2]); + expect(closeEventSpy).toHaveReceivedEventTimes(expectedTimesPerEvent[3]); } if (startOpen) { @@ -191,24 +184,26 @@ async function testOpenCloseEvents({ ); } + async function captureEventTimestamp(eventSpy: EventSpy, eventName: string): Promise { + await eventSpy.next(); + timestamps[toOpenCloseName(eventName)] = Date.now(); + } + const element = await page.find(tag); - await page.waitForChanges(); if (!startOpen) { element.setProperty(openPropName, true); } - await page.waitForChanges(); - await beforeOpenEvent; - await openEvent; + await captureEventTimestamp(beforeOpenEventSpy, eventSequence.at(0)); + await captureEventTimestamp(openEventSpy, eventSequence.at(1)); assertEventSequence([1, 1, 0, 0]); element.setProperty(openPropName, false); - await page.waitForChanges(); - await beforeCloseEvent; - await closeEvent; + await captureEventTimestamp(beforeCloseEventSpy, eventSequence.at(2)); + await captureEventTimestamp(closeEventSpy, eventSequence.at(3)); assertEventSequence([1, 1, 1, 1]); diff --git a/packages/calcite-components/src/tests/commonTests/themed.ts b/packages/calcite-components/src/tests/commonTests/themed.ts index d90fc01d94c..85f9d456da0 100644 --- a/packages/calcite-components/src/tests/commonTests/themed.ts +++ b/packages/calcite-components/src/tests/commonTests/themed.ts @@ -312,6 +312,8 @@ async function assertThemedProps(page: E2EPage, options: TestTarget): Promise](); diff --git a/packages/calcite-components/src/tests/globalStyles.e2e.ts b/packages/calcite-components/src/tests/globalStyles.e2e.ts index 975274347d8..fb47543e102 100644 --- a/packages/calcite-components/src/tests/globalStyles.e2e.ts +++ b/packages/calcite-components/src/tests/globalStyles.e2e.ts @@ -1,15 +1,17 @@ import { newE2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; import { describe, expect, it } from "vitest"; import { html } from "../../support/formatting"; + describe("global styles", () => { describe("animation", () => { - const snippet = ` + const snippet = html`
Hello world
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna. -

+        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
+        magna.
       
`; + const globalClasses = [ "calcite-animate__in", "calcite-animate__in-down", @@ -17,30 +19,30 @@ describe("global styles", () => { "calcite-animate__in-left", "calcite-animate__in-right", "calcite-animate__in-scale", - ]; + ] as const; globalClasses.forEach((className) => { it(`should support rendering component with ${className} animation`, async () => { - const page = await newE2EPage({ html: snippet }); + const page = await newE2EPage(); + await page.setContent(snippet); const element = await page.find("calcite-notice"); - await element.setProperty("active", true); - await element.classList.add(className); + element.classList.add(className); await page.waitForChanges(); - const noticeAnimation = await page.evaluate(() => { - const noticeEl = document.querySelector("calcite-notice"); - if (!noticeEl) { - return null; - } - const { animationName, animationDuration, opacity } = window.getComputedStyle(noticeEl); + element.setProperty("active", true); + await page.waitForChanges(); + + const noticeAnimation = await page.$eval("calcite-notice", (noticeEl) => { + const { animationName: name, animationDuration: duration, opacity } = window.getComputedStyle(noticeEl); return { - name: animationName, - duration: animationDuration, - opacity: opacity, + name, + duration, + opacity, }; }); - expect(noticeAnimation?.duration).toEqual("0.15s"); - expect(noticeAnimation?.name).toEqual(className.slice(className.indexOf("_") + 2)); - expect(noticeAnimation?.opacity).not.toBe("0"); + + expect(noticeAnimation.duration).toEqual("0.15s"); + expect(noticeAnimation.name).toEqual(className.slice(className.indexOf("_") + 2)); + expect(noticeAnimation.opacity).not.toBe("0"); }); }); @@ -60,11 +62,8 @@ describe("global styles", () => { `, }); await page.waitForChanges(); - const eleTransitionDuration = await page.evaluate(() => { - const ele = document.querySelector("div"); - return ele ? window.getComputedStyle(ele).transitionDuration : null; - }); - expect(eleTransitionDuration).toEqual("0s"); + const elTransitionDuration = await page.$eval("div", (el) => window.getComputedStyle(el).transitionDuration); + expect(elTransitionDuration).toEqual("0s"); }); }); @@ -73,24 +72,18 @@ describe("global styles", () => { html: html`
`, }); await page.waitForChanges(); - await page.$eval("div", (element: any) => { - element.style.setProperty("--calcite-duration-factor", 0); + await page.$eval("div", (element) => { + element.style.setProperty("--calcite-duration-factor", "0"); }); - const eleTransitionDuration = await page.evaluate(() => { - const ele = document.querySelector("div"); - return ele ? window.getComputedStyle(ele).transitionDuration : null; - }); - expect(eleTransitionDuration).toEqual("0.15s"); + const elTransitionDuration = await page.$eval("div", (el) => window.getComputedStyle(el).transitionDuration); + expect(elTransitionDuration).toEqual("0.15s"); }); it("should set animation duration to default value 150ms", async () => { const page = await newE2EPage({ html: html`
`, }); - const eleTransitionDuration = await page.evaluate(() => { - const ele = document.querySelector("div"); - return ele ? window.getComputedStyle(ele).transitionDuration : null; - }); - expect(eleTransitionDuration).toEqual("0.15s"); + const elTransitionDuration = await page.$eval("div", (el) => window.getComputedStyle(el).transitionDuration); + expect(elTransitionDuration).toEqual("0.15s"); }); }); diff --git a/packages/calcite-components/src/tests/stackedFocusTrap.e2e.ts b/packages/calcite-components/src/tests/stackedFocusTrap.e2e.ts index b02b6185fd6..26bb16b80ea 100644 --- a/packages/calcite-components/src/tests/stackedFocusTrap.e2e.ts +++ b/packages/calcite-components/src/tests/stackedFocusTrap.e2e.ts @@ -4,7 +4,7 @@ import { describe, expect, it } from "vitest"; import { html } from "../../support/formatting"; import { IDS } from "../components/panel/resources"; import { CSS } from "../components/input-time-picker/resources"; -import { skipAnimations } from "./utils/puppeteer"; +import { skipAnimations, waitForAnimationFrame } from "./utils/puppeteer"; import { mockConsole } from "./utils/logging"; describe("stacked focus-trap components", () => { @@ -63,20 +63,23 @@ describe("stacked focus-trap components", () => { await page.setContent(componentStack); await skipAnimations(page); - async function testStackEscapeSequence(page: E2EPage, pickerType: string): Promise { + async function testStackEscapeSequence( + page: E2EPage, + pickerType: "calcite-input-date-picker" | "calcite-input-time-picker", + ): Promise { async function openAndCheckVisibility(element: E2EElement): Promise { const elTagNameCamelCased = camelCase(element.tagName); - const openEvent = page.waitForEvent(`${elTagNameCamelCased}Open`); + const openEventSpy = await page.spyOnEvent(`${elTagNameCamelCased}Open`); element.setProperty("open", true); await page.waitForChanges(); - await openEvent; + await openEventSpy.next(); } async function testEscapeAndAssertOpenState(focusTrapOrderElements: E2EElement[]): Promise { for (let i = 0; i < focusTrapOrderElements.length; i++) { const elTagNameCamelCased = camelCase(focusTrapOrderElements[i].tagName); - const closeEvent = page.waitForEvent(`${elTagNameCamelCased}Close`); + const closeEventSpy = await page.spyOnEvent(`${elTagNameCamelCased}Close`); const activeElementId = await page.evaluate(() => document.activeElement?.id); @@ -104,7 +107,7 @@ describe("stacked focus-trap components", () => { await page.keyboard.press("Escape"); await page.waitForChanges(); - await closeEvent; + await closeEventSpy.next(); expect(await focusTrapOrderElements[i].getProperty("open")).toBe(false); @@ -120,7 +123,7 @@ describe("stacked focus-trap components", () => { const firstModal = await page.find("#example-modal"); const secondModal = await page.find("#another-modal"); const popover = await page.find("#popover"); - const inputPicker = await page.find(pickerType); + const inputTimeOrDatePicker = await page.find(pickerType); await openAndCheckVisibility(sheet); await openAndCheckVisibility(dialog); @@ -131,10 +134,14 @@ describe("stacked focus-trap components", () => { const clickTarget = pickerType === "calcite-input-time-picker" ? await page.find(`calcite-input-time-picker >>> .${CSS.toggleIcon}`) - : inputPicker; + : inputTimeOrDatePicker; await clickTarget.click(); + await page.waitForChanges(); + // intentional double wait waitForAnimationFrame to ensure focus shift + await waitForAnimationFrame(page); + await waitForAnimationFrame(page); - await testEscapeAndAssertOpenState([inputPicker, popover, secondModal, firstModal, dialog, sheet]); + await testEscapeAndAssertOpenState([inputTimeOrDatePicker, popover, secondModal, firstModal, dialog, sheet]); } await testStackEscapeSequence(page, "calcite-input-time-picker"); @@ -164,16 +171,15 @@ describe("returning focus after deactivation", () => { const dialog = await page.find("#dialog"); const elTagNameCamelCased = camelCase(dialog.tagName); - const openEvent = page.waitForEvent(`${elTagNameCamelCased}Open`); + const openEventSpy = await page.spyOnEvent(`${elTagNameCamelCased}Open`); dialog.setProperty("open", true); await page.waitForChanges(); - await openEvent; + await openEventSpy.next(); - const closeEvent = page.waitForEvent(`${elTagNameCamelCased}Close`); + const closeEventSpy = await page.spyOnEvent(`${elTagNameCamelCased}Close`); dialog.press("Escape"); - await page.waitForChanges(); - await closeEvent; + await closeEventSpy.next(); const activeElementId = await page.evaluate(() => document.activeElement?.id); expect(activeElementId).toBe(openButton.id); @@ -190,17 +196,16 @@ describe("returning focus after deactivation", () => { const dialog = await page.find("#dialog"); const elTagNameCamelCased = camelCase(dialog.tagName); - const openEvent = page.waitForEvent(`${elTagNameCamelCased}Open`); + const openEventSpy = await page.spyOnEvent(`${elTagNameCamelCased}Open`); dialog.setProperty("open", true); await page.waitForChanges(); - await openEvent; + await openEventSpy.next(); - const closeEvent = page.waitForEvent(`${elTagNameCamelCased}Close`); + const closeEventSpy = await page.spyOnEvent(`${elTagNameCamelCased}Close`); const closeButton = await page.find(`calcite-dialog >>> calcite-panel >>> #${IDS.close}`); await closeButton.click(); - await page.waitForChanges(); - await closeEvent; + await closeEventSpy.next(); const activeElementId = await page.evaluate(() => document.activeElement?.id); expect(activeElementId).toBe(openButton.id); @@ -217,11 +222,11 @@ describe("returning focus after deactivation", () => { const dialog = await page.find("#dialog"); const elTagNameCamelCased = camelCase(dialog.tagName); - const openEvent = page.waitForEvent(`${elTagNameCamelCased}Open`); + const openEventSpy = await page.spyOnEvent(`${elTagNameCamelCased}Open`); dialog.setProperty("open", true); await page.waitForChanges(); - await openEvent; + await openEventSpy.next(); const outsideButton = await page.find("#other-button"); await outsideButton.click(); diff --git a/packages/calcite-components/src/tests/utils/puppeteer.ts b/packages/calcite-components/src/tests/utils/puppeteer.ts index eb9e935098c..5d3f063cc03 100644 --- a/packages/calcite-components/src/tests/utils/puppeteer.ts +++ b/packages/calcite-components/src/tests/utils/puppeteer.ts @@ -4,6 +4,7 @@ import { LitElement, LuminaJsx, ToElement } from "@arcgis/lumina"; import { E2EElement, E2EPage, newE2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; import { expect } from "vitest"; import { ComponentTag } from "../commonTests/interfaces"; +import { waitForAnimationFrame as waitForRaf } from "./timing"; /** Util to help type global props for testing. */ export type GlobalTestProps = T & Window & typeof globalThis; @@ -281,7 +282,16 @@ export async function visualizeMouseCursor(page: E2EPage): Promise { }); } -export { waitForAnimationFrame } from "./timing"; +/** + * Helper function to wait for the next animation frame within the Puppeteer browser context. + * + * If you need to run this without Puppeteer dependencies, you can use the `waitForAnimationFrame` function from the `timing` module. + * + * @param page + */ +export async function waitForAnimationFrame(page: E2EPage): Promise { + await page.evaluate(waitForRaf); +} /** * Creates an E2E page for tests that need to create and set up elements programmatically. diff --git a/packages/calcite-components/src/tests/utils/timing.ts b/packages/calcite-components/src/tests/utils/timing.ts index dbb26c79048..8b7cd66bce3 100644 --- a/packages/calcite-components/src/tests/utils/timing.ts +++ b/packages/calcite-components/src/tests/utils/timing.ts @@ -1,6 +1,7 @@ /** - * Tells the browser that you wish to perform an animation. - * https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame + * Helper function to wait for the next animation frame. + * + * If you need to run this within a Puppeteer browser context, please see the `waitForAnimationFrame` function in the `puppeteer` module. * * @returns {Promise} */ diff --git a/packages/calcite-components/src/utils/dom.spec.ts b/packages/calcite-components/src/utils/dom.spec.ts index 89f403c0edf..df52dbc6e46 100644 --- a/packages/calcite-components/src/utils/dom.spec.ts +++ b/packages/calcite-components/src/utils/dom.spec.ts @@ -2,7 +2,7 @@ import { beforeAll, beforeEach, describe, expect, it, Mock, vi } from "vitest"; import { ModeName } from "../components/interfaces"; import { html } from "../../support/formatting"; -import { waitForAnimationFrame } from "../tests/utils/puppeteer"; +import { waitForAnimationFrame } from "../tests/utils/timing"; import { createControlledPromise } from "../tests/utils/promises"; import { guidPattern } from "./guid.spec"; import { diff --git a/packages/calcite-components/src/utils/floating-ui.spec.ts b/packages/calcite-components/src/utils/floating-ui.spec.ts index 8d87f6b540d..c6b8dcfb421 100644 --- a/packages/calcite-components/src/utils/floating-ui.spec.ts +++ b/packages/calcite-components/src/utils/floating-ui.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, it, beforeEach, vi } from "vitest"; -import { waitForAnimationFrame } from "../tests/utils/puppeteer"; +import { waitForAnimationFrame } from "../tests/utils/timing"; import { mockConsole } from "../tests/utils/logging"; import { DEBOUNCE } from "./resources"; import * as floatingUI from "./floating-ui"; diff --git a/packages/calcite-components/src/utils/openCloseComponent.spec.ts b/packages/calcite-components/src/utils/openCloseComponent.spec.ts index 3cc2bef031f..29b8286d537 100644 --- a/packages/calcite-components/src/utils/openCloseComponent.spec.ts +++ b/packages/calcite-components/src/utils/openCloseComponent.spec.ts @@ -1,5 +1,5 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { waitForAnimationFrame } from "../tests/utils/puppeteer"; +import { waitForAnimationFrame } from "../tests/utils/timing"; import { createControlledPromise } from "../tests/utils/promises"; import * as openCloseComponent from "./openCloseComponent";