diff --git a/modules/react/tooltip/lib/OverflowTooltip.tsx b/modules/react/tooltip/lib/OverflowTooltip.tsx index 9784d12352..3eb39992ec 100644 --- a/modules/react/tooltip/lib/OverflowTooltip.tsx +++ b/modules/react/tooltip/lib/OverflowTooltip.tsx @@ -55,6 +55,11 @@ export const findEllipsisElement = (element: Element): Element | null => { } }; +const getInnerText = (element: Element): string => { + const ownerWindow = element.ownerDocument?.defaultView; + return ownerWindow && element instanceof ownerWindow.HTMLElement ? element.innerText : ''; +}; + const isOverflowed = (element: Element) => { const overflowElement = findEllipsisElement(element) || findOverflowElement(element); @@ -134,14 +139,14 @@ export const OverflowTooltip = ({ const onMouseEnter = (event: React.MouseEvent) => { const target = event.currentTarget; - setTitleText(target instanceof HTMLElement ? target.innerText : ''); + setTitleText(getInnerText(target)); if (isOverflowed(target)) { targetProps.onMouseEnter(event as React.MouseEvent); } }; const onFocus = (event: React.FocusEvent) => { const target = event.currentTarget; - setTitleText(target instanceof HTMLElement ? target.innerText : ''); + setTitleText(getInnerText(target)); if (isOverflowed(target)) { targetProps.onFocus(event as React.FocusEvent); } diff --git a/modules/react/tooltip/spec/OverflowTooltip.spec.tsx b/modules/react/tooltip/spec/OverflowTooltip.spec.tsx index f618884c0c..d0af9a9366 100644 --- a/modules/react/tooltip/spec/OverflowTooltip.spec.tsx +++ b/modules/react/tooltip/spec/OverflowTooltip.spec.tsx @@ -1,4 +1,4 @@ -import {fireEvent, render, screen} from '@testing-library/react'; +import {fireEvent, render, screen, within} from '@testing-library/react'; import {act} from 'react-dom/test-utils'; import {OverflowTooltip, findEllipsisElement, findOverflowElement} from '..'; @@ -29,6 +29,7 @@ describe('OverflowTooltip', () => { const markAsOverflowed = (target: HTMLElement) => { Object.defineProperty(target, 'scrollWidth', {configurable: true, value: 200}); Object.defineProperty(target, 'clientWidth', {configurable: true, value: 100}); + Object.defineProperty(target, 'innerText', {configurable: true, value: target.textContent}); }; it('should render the tooltip after the delay when "showDelay" is passed', () => { @@ -54,6 +55,57 @@ describe('OverflowTooltip', () => { expect(screen.getByRole('tooltip')).toBeInTheDocument(); }); + it('should show the target text in the tooltip when the target is overflowed', () => { + render( + + Overflowed Text + + ); + + const target = screen.getByText('Overflowed Text'); + markAsOverflowed(target); + + fireEvent.mouseEnter(target); + + act(() => { + vi.advanceTimersByTime(500); + }); + expect(screen.getByRole('tooltip')).toHaveTextContent('Overflowed Text'); + }); + + it('should show the target text when the target is in a different window realm', () => { + const testWindow = document.createElement('iframe'); + document.body.appendChild(testWindow); + + const containerBody = testWindow.contentDocument?.body; + if (!containerBody) { + throw new Error('iframe contentDocument not available'); + } + + const {unmount} = render( + + Overflowed Text + , + {container: containerBody} + ); + + try { + const target = within(containerBody).getByText('Overflowed Text'); + markAsOverflowed(target); + + fireEvent.mouseEnter(target); + + act(() => { + vi.advanceTimersByTime(500); + }); + // Use textContent directly: toHaveTextContent() uses instanceof Node and fails across window realms + expect(within(containerBody).getByRole('tooltip').textContent).toBe('Overflowed Text'); + } finally { + unmount(); + testWindow.remove(); + } + }); + it('should hide the tooltip after the delay when "hideDelay" is passed', () => { render(