diff --git a/packages/calcite-components/src/components/tooltip/TooltipManager.ts b/packages/calcite-components/src/components/tooltip/TooltipManager.ts index 9f6149749d7..f34696cf83e 100644 --- a/packages/calcite-components/src/components/tooltip/TooltipManager.ts +++ b/packages/calcite-components/src/components/tooltip/TooltipManager.ts @@ -215,6 +215,11 @@ export default class TooltipManager { } this.clearHoverCloseTimeout(); + + if (this.activeTooltip === this.hoveredTooltip) { + return; + } + this.closeActiveTooltip(); if (tooltip !== this.hoveredTooltip) { diff --git a/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts b/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts index 38826a6568c..3a37b1b079d 100644 --- a/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts +++ b/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts @@ -2,7 +2,7 @@ import { E2EPage, newE2EPage } from "@stencil/core/testing"; import { TOOLTIP_OPEN_DELAY_MS, TOOLTIP_CLOSE_DELAY_MS } from "../tooltip/resources"; import { accessible, defaults, hidden, floatingUIOwner, renders } from "../../tests/commonTests"; import { html } from "../../../support/formatting"; -import { GlobalTestProps } from "../../tests/utils"; +import { getElementXY, GlobalTestProps } from "../../tests/utils"; interface PointerMoveOptions { delay: number; @@ -677,59 +677,112 @@ describe("calcite-tooltip", () => { expect(await tooltip.isVisible()).toBe(true); }); - it("should emit open and beforeOpen events", async () => { - const page = await newE2EPage(); - await page.setContent( - `content
referenceElement
` - ); - const tooltip = await page.find("calcite-tooltip"); - - const openEvent = await tooltip.spyOnEvent("calciteTooltipOpen"); - const beforeOpenEvent = await tooltip.spyOnEvent("calciteTooltipBeforeOpen"); + describe("beforeOpen, open, beforeClose, close event emitting", () => { + it("emits via prop", async () => { + await assertEventEmitting({ + openTooltip: async (page) => { + const tooltipBeforeOpenEvent = page.waitForEvent("calciteTooltipBeforeOpen"); + const tooltipOpenEvent = page.waitForEvent("calciteTooltipOpen"); + const tooltip = await page.find("calcite-tooltip"); - expect(openEvent).toHaveReceivedEventTimes(0); - expect(beforeOpenEvent).toHaveReceivedEventTimes(0); + tooltip.setProperty("open", true); + await page.waitForChanges(); - const tooltipOpenEvent = page.waitForEvent("calciteTooltipOpen"); - const tooltipBeforeOpenEvent = page.waitForEvent("calciteTooltipBeforeOpen"); + await tooltipBeforeOpenEvent; + await tooltipOpenEvent; + }, + closeTooltip: async (page) => { + const tooltipBeforeCloseEvent = page.waitForEvent("calciteTooltipBeforeClose"); + const tooltipCloseEvent = page.waitForEvent("calciteTooltipClose"); + const tooltip = await page.find("calcite-tooltip"); - tooltip.setProperty("open", true); - await page.waitForChanges(); + tooltip.setProperty("open", false); + await page.waitForChanges(); - await tooltipOpenEvent; - await tooltipBeforeOpenEvent; + await tooltipBeforeCloseEvent; + await tooltipCloseEvent; + }, + }); + }); - expect(openEvent).toHaveReceivedEventTimes(1); - expect(beforeOpenEvent).toHaveReceivedEventTimes(1); - }); + it("emits via mouse", async () => { + const moveOptions = { steps: 10 }; + const totalDelayFromMoveSteps = TOOLTIP_OPEN_DELAY_MS * moveOptions.steps; + const xMoveOffset = 25; - it("should emit close and beforeClose events", async () => { - const page = await newE2EPage(); - await page.setContent( - `content
referenceElement
` - ); + await assertEventEmitting({ + openTooltip: async (page: E2EPage) => { + const [refElementX, refElementY] = await getElementXY(page, "#ref"); - const tooltip = await page.find("calcite-tooltip"); + await page.mouse.move(0, 0, moveOptions); + await page.mouse.move(refElementX, refElementY, moveOptions); + await page.mouse.move(refElementX + xMoveOffset, refElementY, moveOptions); + await page.waitForChanges(); - const closeEvent = await tooltip.spyOnEvent("calciteTooltipClose"); - const beforeCloseEvent = await tooltip.spyOnEvent("calciteTooltipBeforeClose"); + await page.waitForTimeout(totalDelayFromMoveSteps); + }, + closeTooltip: async (page: E2EPage) => { + const [refElementX, refElementY] = await getElementXY(page, "#ref"); - expect(closeEvent).toHaveReceivedEventTimes(0); - expect(beforeCloseEvent).toHaveReceivedEventTimes(0); + await page.mouse.move(refElementX + xMoveOffset, refElementY, moveOptions); + await page.mouse.move(refElementX, refElementY, moveOptions); + await page.mouse.move(0, 0, moveOptions); + await page.waitForChanges(); - const tooltipCloseEvent = page.waitForEvent("calciteTooltipClose"); - const tooltipBeforeCloseEvent = page.waitForEvent("calciteTooltipBeforeClose"); + await page.waitForTimeout(totalDelayFromMoveSteps); + }, + }); + }); - await page.evaluate(() => { - const tooltip = document.querySelector("calcite-tooltip"); - tooltip.open = false; + it("emits via keyboard", async () => { + await assertEventEmitting({ + openTooltip: async (page) => { + await page.keyboard.press("Tab"); + await page.waitForChanges(); + }, + closeTooltip: async (page) => { + await page.keyboard.press("Tab"); + await page.waitForChanges(); + }, + }); }); - await tooltipBeforeCloseEvent; - await tooltipCloseEvent; + async function assertEventEmitting(params: { + openTooltip: (page: E2EPage) => Promise; + closeTooltip: (page: E2EPage) => Promise; + }): Promise { + const page = await newE2EPage(); + await page.setContent( + `content` + ); + 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"); + + expect(beforeOpenEvent).toHaveReceivedEventTimes(0); + expect(openEvent).toHaveReceivedEventTimes(0); + expect(beforeCloseEvent).toHaveReceivedEventTimes(0); + expect(closeEvent).toHaveReceivedEventTimes(0); + + await params.openTooltip(page); + await page.waitForChanges(); + + expect(beforeOpenEvent).toHaveReceivedEventTimes(1); + expect(openEvent).toHaveReceivedEventTimes(1); + expect(beforeCloseEvent).toHaveReceivedEventTimes(0); + expect(closeEvent).toHaveReceivedEventTimes(0); + + await params.closeTooltip(page); + await page.waitForChanges(); - expect(closeEvent).toHaveReceivedEventTimes(1); - expect(beforeCloseEvent).toHaveReceivedEventTimes(1); + expect(beforeOpenEvent).toHaveReceivedEventTimes(1); + expect(openEvent).toHaveReceivedEventTimes(1); + expect(beforeCloseEvent).toHaveReceivedEventTimes(1); + expect(closeEvent).toHaveReceivedEventTimes(1); + } }); it.skip("should open hovered tooltip while pointer is moving", async () => {