Skip to content

Commit

Permalink
fix(tooltip): avoid extra before open/close event emitting (#7422)
Browse files Browse the repository at this point in the history
**Related Issue:** #7396

## Summary

Updates `TooltipManager` logic to avoid toggling hovered tooltips if
they are the active ones.
  • Loading branch information
jcfranco authored Aug 3, 2023
1 parent 9a53b6a commit dbb6818
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,11 @@ export default class TooltipManager {
}

this.clearHoverCloseTimeout();

if (this.activeTooltip === this.hoveredTooltip) {
return;
}

this.closeActiveTooltip();

if (tooltip !== this.hoveredTooltip) {
Expand Down
133 changes: 93 additions & 40 deletions packages/calcite-components/src/components/tooltip/tooltip.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(
`<calcite-tooltip placement="auto" reference-element="ref">content</calcite-tooltip><div id="ref">referenceElement</div>`
);
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(
`<calcite-tooltip placement="auto" reference-element="ref" open>content</calcite-tooltip><div id="ref">referenceElement</div>`
);
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<void>;
closeTooltip: (page: E2EPage) => Promise<void>;
}): Promise<void> {
const page = await newE2EPage();
await page.setContent(
`<calcite-tooltip placement="auto" reference-element="ref">content</calcite-tooltip><button id="ref">referenceElement</button>`
);
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 () => {
Expand Down

0 comments on commit dbb6818

Please sign in to comment.