diff --git a/packages/components/src/Tooltip/Tooltip.module.css b/packages/components/src/Tooltip/Tooltip.module.css index 45e98a2184..a91d51d54a 100644 --- a/packages/components/src/Tooltip/Tooltip.module.css +++ b/packages/components/src/Tooltip/Tooltip.module.css @@ -92,3 +92,7 @@ font-weight: 500; line-height: var(--typography--lineHeight-base); } + +.hidden { + display: none; +} diff --git a/packages/components/src/Tooltip/Tooltip.module.css.d.ts b/packages/components/src/Tooltip/Tooltip.module.css.d.ts index 96d01d3874..aabf220268 100644 --- a/packages/components/src/Tooltip/Tooltip.module.css.d.ts +++ b/packages/components/src/Tooltip/Tooltip.module.css.d.ts @@ -8,6 +8,7 @@ declare const styles: { readonly "left": string; readonly "right": string; readonly "tooltipMessage": string; + readonly "hidden": string; }; export = styles; diff --git a/packages/components/src/Tooltip/Tooltip.test.tsx b/packages/components/src/Tooltip/Tooltip.test.tsx index f676c21241..458ee5084b 100644 --- a/packages/components/src/Tooltip/Tooltip.test.tsx +++ b/packages/components/src/Tooltip/Tooltip.test.tsx @@ -4,6 +4,31 @@ import userEvent from "@testing-library/user-event"; import { Tooltip } from "."; import { mockLargeViewport } from "../utils/mockLargeViewport"; +let viewportMock: ReturnType; + +beforeEach(() => { + viewportMock = mockLargeViewport(); + // Ensures the tooltip is considered visible within the viewport + jest + .spyOn(Element.prototype, "getBoundingClientRect") + .mockImplementation(() => ({ + width: 100, + height: 50, + x: 500, + y: 500, + top: 500, + left: 500, + bottom: 550, + right: 600, + toJSON: () => ({}), + })); +}); + +afterEach(() => { + viewportMock.restore(); + jest.restoreAllMocks(); +}); + it("shouldn't show the tooltip", async () => { const message = "Imma not tip the tool"; const content = "Don't show my tooltip"; @@ -122,16 +147,6 @@ describe("with a message of an empty string", () => { }); describe("with a preferred placement", () => { - let viewportMock: ReturnType; - - beforeEach(() => { - viewportMock = mockLargeViewport(); - }); - - afterEach(() => { - viewportMock.restore(); - }); - it.each(["top", "bottom", "left", "right"] as const)( "should show the tooltip on the %s", async placement => { @@ -155,3 +170,52 @@ describe("with a preferred placement", () => { }, ); }); + +describe("tooltip visibility", () => { + it("visible when in view", async () => { + const message = "Visible tooltip"; + + render( + +
tooltip test
+
, + ); + + const tooltipContent = screen.getByText("tooltip test"); + await userEvent.hover(tooltipContent); + + const tooltip = screen.getByRole("tooltip"); + expect(tooltip).toBeInTheDocument(); + }); + + it("hidden when out of view", async () => { + const message = "Hidden tooltip"; + + // Force the tooltip to be outside of the viewport + jest + .spyOn(Element.prototype, "getBoundingClientRect") + .mockImplementation(() => ({ + width: 100, + height: 50, + x: -500, + y: -500, + top: -500, + left: -500, + bottom: -450, + right: -400, + toJSON: () => ({}), + })); + + render( + +
tooltip test
+
, + ); + + const tooltipContent = screen.getByText("tooltip test"); + await userEvent.hover(tooltipContent); + + const tooltip = screen.getByRole("tooltip", { hidden: true }); + expect(tooltip).not.toBeVisible(); + }); +}); diff --git a/packages/components/src/Tooltip/Tooltip.tsx b/packages/components/src/Tooltip/Tooltip.tsx index ebf3fa6ef7..c4aa6c4f1d 100644 --- a/packages/components/src/Tooltip/Tooltip.tsx +++ b/packages/components/src/Tooltip/Tooltip.tsx @@ -42,6 +42,7 @@ export function Tooltip({ styles: floatingStyles, setArrowRef, setTooltipRef, + isHidden, } = useTooltipPositioning({ preferredPlacement: preferredPlacement }); initializeListeners(); @@ -52,6 +53,7 @@ export function Tooltip({ placement === "top" && styles.top, placement === "left" && styles.left, placement === "right" && styles.right, + isHidden && styles.hidden, ); const arrowX = floatingStyles.arrow?.x; @@ -79,6 +81,7 @@ export function Tooltip({ style={floatingStyles.float} ref={setTooltipRef} role="tooltip" + hidden={isHidden} data-placement={placement} > { return ( - +
- Tooltip Examples + Tooltip Examples - {/* Basic Tooltip */} -
- Basic Tooltip - - - -
+ Basic +
+ +
- {/* Tooltip Positions */} -
- Tooltip Positions - - - - -
+ Positions + + +
-
+ ); }; diff --git a/packages/site/tests/visual/site.visual.ts b/packages/site/tests/visual/site.visual.ts index e842ff090c..4938ee7209 100644 --- a/packages/site/tests/visual/site.visual.ts +++ b/packages/site/tests/visual/site.visual.ts @@ -315,14 +315,6 @@ test.describe("Atlantis Visual Tests", () => { }); }); - test("tooltip components", { tag: "@Tooltip" }, async ({ page }) => { - await page.goto("/visual-tests/tooltip"); - await page.waitForTimeout(500); - await expect(page).toHaveScreenshot("visual-test-tooltip-page.png", { - fullPage: true, - }); - }); - /* We have a font rendering issue between local and CI with JobberPro. diff --git a/packages/site/tests/visual/site.visual.ts-snapshots/visual-test-tooltip-page-chromium.png b/packages/site/tests/visual/site.visual.ts-snapshots/visual-test-tooltip-page-chromium.png deleted file mode 100644 index ebf2235c73..0000000000 Binary files a/packages/site/tests/visual/site.visual.ts-snapshots/visual-test-tooltip-page-chromium.png and /dev/null differ diff --git a/packages/site/tests/visual/site.visual.ts-snapshots/visual-test-tooltip-page-firefox.png b/packages/site/tests/visual/site.visual.ts-snapshots/visual-test-tooltip-page-firefox.png deleted file mode 100644 index d0f8f20923..0000000000 Binary files a/packages/site/tests/visual/site.visual.ts-snapshots/visual-test-tooltip-page-firefox.png and /dev/null differ diff --git a/packages/site/tests/visual/site.visual.ts-snapshots/visual-test-tooltip-page-webkit.png b/packages/site/tests/visual/site.visual.ts-snapshots/visual-test-tooltip-page-webkit.png deleted file mode 100644 index 9e8fec3fd0..0000000000 Binary files a/packages/site/tests/visual/site.visual.ts-snapshots/visual-test-tooltip-page-webkit.png and /dev/null differ diff --git a/packages/site/tests/visual/tooltip.visual.ts b/packages/site/tests/visual/tooltip.visual.ts new file mode 100644 index 0000000000..aae2954922 --- /dev/null +++ b/packages/site/tests/visual/tooltip.visual.ts @@ -0,0 +1,87 @@ +import { expect, test } from "@playwright/test"; + +test.describe("Tooltip Visual Tests", () => { + test.beforeEach(async ({ page }) => { + await page.goto("/visual-tests/tooltip"); + await page.waitForTimeout(500); + await page.setViewportSize({ width: 1024, height: 1000 }); + }); + + test("should capture initial page state", async ({ page }) => { + await expect(page).toHaveScreenshot("initial-page.png", { + fullPage: true, + }); + }); + + test.describe("tooltip positions", () => { + test("top", async ({ page }) => { + const tooltipTrigger = await page.getByRole("button", { name: "Top" }); + await tooltipTrigger.hover(); + await expect(page.getByRole("tooltip")).toBeVisible(); + await expect(page).toHaveScreenshot("top-tooltip.png", { + fullPage: true, + }); + }); + + test("bottom", async ({ page }) => { + const tooltipTrigger = await page.getByRole("button", { name: "Bottom" }); + await tooltipTrigger.hover(); + await expect(page.getByRole("tooltip")).toBeVisible(); + await expect(page).toHaveScreenshot("bottom-tooltip.png", { + fullPage: true, + }); + }); + + test("right", async ({ page }) => { + const tooltipTrigger = await page.getByRole("button", { name: "Right" }); + await tooltipTrigger.hover(); + await expect(page.getByRole("tooltip")).toBeVisible(); + await expect(page).toHaveScreenshot("right-tooltip.png", { + fullPage: true, + }); + }); + + test("left", async ({ page }) => { + const tooltipTrigger = await page.getByRole("button", { name: "Left" }); + await tooltipTrigger.hover(); + await expect(page.getByRole("tooltip")).toBeVisible(); + await expect(page).toHaveScreenshot("left-tooltip.png", { + fullPage: true, + }); + }); + }); + + test("large text", async ({ page }) => { + const tooltipTrigger = await page.getByRole("button", { + name: "Long Message", + }); + await tooltipTrigger.hover(); + await expect(page.getByRole("tooltip")).toBeVisible(); + await expect(page).toHaveScreenshot("large-text-tooltip.png", { + fullPage: true, + }); + }); + + test.describe("offscreen and within a scrollable container", () => { + test("tooltip should not be visible", async ({ page }) => { + const tooltipTrigger = await page.getByRole("button", { + name: "Offscreen", + }); + const scrollableContainer = page.getByTestId("scrollable-container"); + + // Focusing the button brings the tooltip into view + await tooltipTrigger.focus(); + await expect(page.getByRole("tooltip")).toBeVisible(); + + // Scrolling the button out of view should hide the tooltip + await scrollableContainer.evaluate(el => { + el.scrollTop = 0; + }); + await expect(page.getByRole("tooltip")).not.toBeVisible(); + + await expect(page).toHaveScreenshot("offscreen-tooltip.png", { + fullPage: true, + }); + }); + }); +}); diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/bottom-tooltip-chromium.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/bottom-tooltip-chromium.png new file mode 100644 index 0000000000..6afd32688c Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/bottom-tooltip-chromium.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/bottom-tooltip-firefox.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/bottom-tooltip-firefox.png new file mode 100644 index 0000000000..bd0265c6ad Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/bottom-tooltip-firefox.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/bottom-tooltip-webkit.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/bottom-tooltip-webkit.png new file mode 100644 index 0000000000..749fc5a72f Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/bottom-tooltip-webkit.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/initial-page-chromium.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/initial-page-chromium.png new file mode 100644 index 0000000000..ec06f96dbe Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/initial-page-chromium.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/initial-page-firefox.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/initial-page-firefox.png new file mode 100644 index 0000000000..879ebc881a Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/initial-page-firefox.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/initial-page-webkit.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/initial-page-webkit.png new file mode 100644 index 0000000000..aacf81dcb9 Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/initial-page-webkit.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/large-text-tooltip-chromium.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/large-text-tooltip-chromium.png new file mode 100644 index 0000000000..78ae0ec131 Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/large-text-tooltip-chromium.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/large-text-tooltip-firefox.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/large-text-tooltip-firefox.png new file mode 100644 index 0000000000..09e259e617 Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/large-text-tooltip-firefox.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/large-text-tooltip-webkit.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/large-text-tooltip-webkit.png new file mode 100644 index 0000000000..422862880a Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/large-text-tooltip-webkit.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/left-tooltip-chromium.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/left-tooltip-chromium.png new file mode 100644 index 0000000000..0e45374e86 Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/left-tooltip-chromium.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/left-tooltip-firefox.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/left-tooltip-firefox.png new file mode 100644 index 0000000000..f8649fdf43 Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/left-tooltip-firefox.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/left-tooltip-webkit.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/left-tooltip-webkit.png new file mode 100644 index 0000000000..2980a5a560 Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/left-tooltip-webkit.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/offscreen-tooltip-chromium.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/offscreen-tooltip-chromium.png new file mode 100644 index 0000000000..ec06f96dbe Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/offscreen-tooltip-chromium.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/offscreen-tooltip-firefox.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/offscreen-tooltip-firefox.png new file mode 100644 index 0000000000..879ebc881a Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/offscreen-tooltip-firefox.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/offscreen-tooltip-webkit.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/offscreen-tooltip-webkit.png new file mode 100644 index 0000000000..aacf81dcb9 Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/offscreen-tooltip-webkit.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/right-tooltip-chromium.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/right-tooltip-chromium.png new file mode 100644 index 0000000000..852d36e1c1 Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/right-tooltip-chromium.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/right-tooltip-firefox.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/right-tooltip-firefox.png new file mode 100644 index 0000000000..a2078b37b4 Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/right-tooltip-firefox.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/right-tooltip-webkit.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/right-tooltip-webkit.png new file mode 100644 index 0000000000..3fa4541e32 Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/right-tooltip-webkit.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/top-tooltip-chromium.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/top-tooltip-chromium.png new file mode 100644 index 0000000000..09388ef624 Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/top-tooltip-chromium.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/top-tooltip-firefox.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/top-tooltip-firefox.png new file mode 100644 index 0000000000..739920b6be Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/top-tooltip-firefox.png differ diff --git a/packages/site/tests/visual/tooltip.visual.ts-snapshots/top-tooltip-webkit.png b/packages/site/tests/visual/tooltip.visual.ts-snapshots/top-tooltip-webkit.png new file mode 100644 index 0000000000..5cc7fbbd43 Binary files /dev/null and b/packages/site/tests/visual/tooltip.visual.ts-snapshots/top-tooltip-webkit.png differ