From ac4d28fa0baddb66ffe3375d0d96d53b9d0fecbc Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Fri, 22 Dec 2023 16:21:39 +0100 Subject: [PATCH] Add second-level describes --- .../components/src/tooltip/test/index.tsx | 574 ++++++++++-------- 1 file changed, 323 insertions(+), 251 deletions(-) diff --git a/packages/components/src/tooltip/test/index.tsx b/packages/components/src/tooltip/test/index.tsx index da4fb65f1740c..a7011b479831f 100644 --- a/packages/components/src/tooltip/test/index.tsx +++ b/packages/components/src/tooltip/test/index.tsx @@ -42,309 +42,381 @@ const hoverOutside = async () => { }; describe( 'Tooltip', () => { - it( 'should not render the tooltip if multiple children are passed', async () => { - render( - // expected TS error since Tooltip cannot have more than one child element - // @ts-expect-error - - - - - ); - - expect( - screen.getByRole( 'button', { name: 'First button' } ) - ).toBeVisible(); - expect( - screen.getByRole( 'button', { name: 'Second button' } ) - ).toBeVisible(); - - await press.Tab(); - - expectTooltipToBeHidden(); - } ); + describe( 'basic behavior', () => { + it( 'should not render the tooltip if multiple children are passed', async () => { + render( + // expected TS error since Tooltip cannot have more than one child element + // @ts-expect-error + + + + + ); - it( 'should associate the tooltip text with its anchor via the accessible description when visible', async () => { - render( ); + expect( + screen.getByRole( 'button', { name: 'First button' } ) + ).toBeVisible(); + expect( + screen.getByRole( 'button', { name: 'Second button' } ) + ).toBeVisible(); - // The anchor can not be found by querying for its description, - // since that is present only when the tooltip is visible - expect( - screen.queryByRole( 'button', { description: 'tooltip text' } ) - ).not.toBeInTheDocument(); + await press.Tab(); - // Hover the anchor. The tooltip shows and its text is used to describe - // the tooltip anchor - await hover( - screen.getByRole( 'button', { - name: 'Tooltip anchor', - } ) - ); - expect( - await screen.findByRole( 'button', { description: 'tooltip text' } ) - ).toBeInTheDocument(); - - // Hover outside of the anchor, tooltip should hide - await hoverOutside(); - await waitForTooltipToHide(); - expect( - screen.queryByRole( 'button', { description: 'tooltip text' } ) - ).not.toBeInTheDocument(); + expectTooltipToBeHidden(); + } ); + + it( 'should associate the tooltip text with its anchor via the accessible description when visible', async () => { + render( ); + + // The anchor can not be found by querying for its description, + // since that is present only when the tooltip is visible + expect( + screen.queryByRole( 'button', { description: 'tooltip text' } ) + ).not.toBeInTheDocument(); + + // Hover the anchor. The tooltip shows and its text is used to describe + // the tooltip anchor + await hover( + screen.getByRole( 'button', { + name: 'Tooltip anchor', + } ) + ); + expect( + await screen.findByRole( 'button', { + description: 'tooltip text', + } ) + ).toBeInTheDocument(); + + // Hover outside of the anchor, tooltip should hide + await hoverOutside(); + await waitForTooltipToHide(); + expect( + screen.queryByRole( 'button', { description: 'tooltip text' } ) + ).not.toBeInTheDocument(); + } ); } ); - it( 'should not render the tooltip if there is no focus', () => { - render( ); + describe( 'keyboard focus', () => { + it( 'should not render the tooltip if there is no focus', () => { + render( ); - expect( - screen.getByRole( 'button', { name: 'Tooltip anchor' } ) - ).toBeVisible(); + expect( + screen.getByRole( 'button', { name: 'Tooltip anchor' } ) + ).toBeVisible(); - expectTooltipToBeHidden(); - } ); + expectTooltipToBeHidden(); + } ); - it( 'should show the tooltip when focusing on the tooltip anchor and hide it the anchor loses focus', async () => { - render( - <> - - - - ); - - // Focus the anchor, tooltip should show - await press.Tab(); - expect( - screen.getByRole( 'button', { name: 'Tooltip anchor' } ) - ).toHaveFocus(); - await waitForTooltipToShow(); - - // Focus the other button, tooltip should hide - await press.Tab(); - expect( - screen.getByRole( 'button', { name: 'Focus me' } ) - ).toHaveFocus(); - await waitForTooltipToHide(); - } ); + it( 'should show the tooltip when focusing on the tooltip anchor and hide it the anchor loses focus', async () => { + render( + <> + + + + ); + + // Focus the anchor, tooltip should show + await press.Tab(); + expect( + screen.getByRole( 'button', { name: 'Tooltip anchor' } ) + ).toHaveFocus(); + await waitForTooltipToShow(); - it( 'should show the tooltip when the tooltip anchor is hovered and hide it when the cursor stops hovering the anchor', async () => { - render( ); + // Focus the other button, tooltip should hide + await press.Tab(); + expect( + screen.getByRole( 'button', { name: 'Focus me' } ) + ).toHaveFocus(); + await waitForTooltipToHide(); + } ); - const anchor = screen.getByRole( 'button', { name: 'Tooltip anchor' } ); + it( 'should show tooltip when focussing a disabled (but focussable) anchor button', async () => { + render( + <> + + + + + + ); + + const anchor = screen.getByRole( 'button', { + name: 'Tooltip anchor', + } ); - expect( anchor ).toBeVisible(); + expect( anchor ).toBeVisible(); + expect( anchor ).toHaveAttribute( 'aria-disabled', 'true' ); - // Hover over the anchor, tooltip should show - await hover( anchor ); - await waitForTooltipToShow(); + // Focus anchor, tooltip should show + await press.Tab(); + expect( anchor ).toHaveFocus(); + await waitForTooltipToShow(); - // Hover outside of the anchor, tooltip should hide - await hoverOutside(); - await waitForTooltipToHide(); + // Focus another button, tooltip should hide + await press.Tab(); + expect( + screen.getByRole( 'button', { + name: 'Focus me', + } ) + ).toHaveFocus(); + await waitForTooltipToHide(); + } ); } ); - it( 'should hide tooltip when the tooltip anchor is clicked', async () => { - render( ); + describe( 'mouse hover', () => { + it( 'should show the tooltip when the tooltip anchor is hovered and hide it when the cursor stops hovering the anchor', async () => { + render( ); - const anchor = screen.getByRole( 'button', { name: 'Tooltip anchor' } ); + const anchor = screen.getByRole( 'button', { + name: 'Tooltip anchor', + } ); - expect( anchor ).toBeVisible(); + expect( anchor ).toBeVisible(); - // Hover over the anchor, tooltip should show - await hover( anchor ); - await waitForTooltipToShow(); + // Hover over the anchor, tooltip should show + await hover( anchor ); + await waitForTooltipToShow(); - // Click the anchor, tooltip should hide - await click( anchor ); - await waitForTooltipToHide(); - } ); + // Hover outside of the anchor, tooltip should hide + await hoverOutside(); + await waitForTooltipToHide(); + } ); - it( 'should not hide tooltip when the tooltip anchor is clicked and the `hideOnClick` prop is `false', async () => { - render( - <> - - - - ); + it( 'should show tooltip when hovering over a disabled (but focussable) anchor button', async () => { + render( + <> + + + + + + ); + + const anchor = screen.getByRole( 'button', { + name: 'Tooltip anchor', + } ); + + expect( anchor ).toBeVisible(); + expect( anchor ).toHaveAttribute( 'aria-disabled', 'true' ); - const anchor = screen.getByRole( 'button', { name: 'Tooltip anchor' } ); + // Hover over the anchor, tooltip should show + await hover( anchor ); + await waitForTooltipToShow(); - expect( anchor ).toBeVisible(); + // Hover outside of the anchor, tooltip should hide + await hoverOutside(); + await waitForTooltipToHide(); + } ); + } ); - // Hover over the anchor, tooltip should show - await hover( anchor ); - await waitForTooltipToShow(); + describe( 'mouse click', () => { + it( 'should hide tooltip when the tooltip anchor is clicked', async () => { + render( ); - // Click the anchor, tooltip should not hide - await click( anchor ); - await waitForTooltipToShow(); + const anchor = screen.getByRole( 'button', { + name: 'Tooltip anchor', + } ); - // Click another button, tooltip should hide - await click( screen.getByRole( 'button', { name: 'Click me' } ) ); - await waitForTooltipToHide(); - } ); + expect( anchor ).toBeVisible(); - it( 'should respect custom delay prop when showing tooltip', async () => { - const ADDITIONAL_DELAY = 100; + // Hover over the anchor, tooltip should show + await hover( anchor ); + await waitForTooltipToShow(); - render( - - ); + // Click the anchor, tooltip should hide + await click( anchor ); + await waitForTooltipToHide(); + } ); - const anchor = screen.getByRole( 'button', { name: 'Tooltip anchor' } ); - expect( anchor ).toBeVisible(); + it( 'should not hide tooltip when the tooltip anchor is clicked and the `hideOnClick` prop is `false', async () => { + render( + <> + + + + ); - // Hover over the anchor - await hover( anchor ); - expectTooltipToBeHidden(); + const anchor = screen.getByRole( 'button', { + name: 'Tooltip anchor', + } ); - // Advance time by default delay - await sleep( TOOLTIP_DELAY ); + expect( anchor ).toBeVisible(); - // Tooltip hasn't appeared yet - expectTooltipToBeHidden(); + // Hover over the anchor, tooltip should show + await hover( anchor ); + await waitForTooltipToShow(); - // Wait for additional delay for tooltip to appear - await sleep( ADDITIONAL_DELAY ); - await waitForTooltipToShow(); + // Click the anchor, tooltip should not hide + await click( anchor ); + await waitForTooltipToShow(); - // Hover outside of the anchor, tooltip should hide - await hoverOutside(); - await waitForTooltipToHide(); + // Click another button, tooltip should hide + await click( screen.getByRole( 'button', { name: 'Click me' } ) ); + await waitForTooltipToHide(); + } ); } ); - it( 'should show tooltip when the anchor button is disabled but focusable', async () => { - render( - - - - ); + describe( 'delay', () => { + it( 'should respect custom delay prop when showing tooltip', async () => { + const ADDITIONAL_DELAY = 100; - const anchor = screen.getByRole( 'button', { name: 'Tooltip anchor' } ); + render( + + ); - expect( anchor ).toBeVisible(); - expect( anchor ).toHaveAttribute( 'aria-disabled', 'true' ); + const anchor = screen.getByRole( 'button', { + name: 'Tooltip anchor', + } ); + expect( anchor ).toBeVisible(); - // Hover over the anchor, tooltip should show - await hover( anchor ); - await waitForTooltipToShow(); + // Hover over the anchor + await hover( anchor ); + expectTooltipToBeHidden(); - // Hover outside of the anchor, tooltip should hide - await hoverOutside(); - await waitForTooltipToHide(); - } ); + // Advance time by default delay + await sleep( TOOLTIP_DELAY ); - it( 'should not show tooltip if the mouse leaves the tooltip anchor before set delay', async () => { - const onMouseEnterMock = jest.fn(); - const onMouseLeaveMock = jest.fn(); - const HOVER_OUTSIDE_ANTICIPATION = 200; - - render( - - - - ); - - const anchor = screen.getByRole( 'button', { name: 'Tooltip anchor' } ); - expect( anchor ).toBeVisible(); - - // Hover over the anchor, tooltip hasn't appeared yet - await hover( anchor ); - expect( onMouseEnterMock ).toHaveBeenCalledTimes( 1 ); - expectTooltipToBeHidden(); - - // Advance time, tooltip hasn't appeared yet because TOOLTIP_DELAY time - // hasn't passed yet - await sleep( TOOLTIP_DELAY - HOVER_OUTSIDE_ANTICIPATION ); - expectTooltipToBeHidden(); - - // Hover outside of the anchor, tooltip still hasn't appeared yet - await hoverOutside(); - expectTooltipToBeHidden(); - - expect( onMouseEnterMock ).toHaveBeenCalledTimes( 1 ); - expect( onMouseLeaveMock ).toHaveBeenCalledTimes( 1 ); - - // Advance time again, so that we reach the full TOOLTIP_DELAY time - await sleep( HOVER_OUTSIDE_ANTICIPATION ); - - // Tooltip won't show, since the mouse has left the tooltip anchor - expectTooltipToBeHidden(); - } ); + // Tooltip hasn't appeared yet + expectTooltipToBeHidden(); - it( 'should show the shortcut in the tooltip when a string is passed as the shortcut', async () => { - render( ); + // Wait for additional delay for tooltip to appear + await sleep( ADDITIONAL_DELAY ); + await waitForTooltipToShow(); - // Hover over the anchor, tooltip should show - await hover( screen.getByRole( 'button', { name: 'Tooltip anchor' } ) ); - expect( - screen.getByRole( 'tooltip', { - name: 'tooltip text shortcut text', - } ) - ).toBeVisible(); + // Hover outside of the anchor, tooltip should hide + await hoverOutside(); + await waitForTooltipToHide(); + } ); - // Hover outside of the anchor, tooltip should hide - await hoverOutside(); - await waitForTooltipToHide(); - } ); + it( 'should not show tooltip if the mouse leaves the tooltip anchor before set delay', async () => { + const onMouseEnterMock = jest.fn(); + const onMouseLeaveMock = jest.fn(); + const HOVER_OUTSIDE_ANTICIPATION = 200; + + render( + + + + ); + + const anchor = screen.getByRole( 'button', { + name: 'Tooltip anchor', + } ); + expect( anchor ).toBeVisible(); - it( 'should show the shortcut in the tooltip when an object is passed as the shortcut', async () => { - render( - - ); - - // Hover over the anchor, tooltip should show - await hover( screen.getByRole( 'button', { name: 'Tooltip anchor' } ) ); - const tooltip = screen.getByRole( 'tooltip', { - name: 'tooltip text Control + Shift + Comma', - } ); - expect( tooltip ).toBeVisible(); - expect( tooltip ).toHaveTextContent( /⇧⌘,/i ); + // Hover over the anchor, tooltip hasn't appeared yet + await hover( anchor ); + expect( onMouseEnterMock ).toHaveBeenCalledTimes( 1 ); + expectTooltipToBeHidden(); - // Hover outside of the anchor, tooltip should hide - await hoverOutside(); - await waitForTooltipToHide(); - } ); + // Advance time, tooltip hasn't appeared yet because TOOLTIP_DELAY time + // hasn't passed yet + await sleep( TOOLTIP_DELAY - HOVER_OUTSIDE_ANTICIPATION ); + expectTooltipToBeHidden(); + + // Hover outside of the anchor, tooltip still hasn't appeared yet + await hoverOutside(); + expectTooltipToBeHidden(); - it( 'should close the parent dialog component when pressing the Escape key while the tooltip is visible', async () => { - const onRequestClose = jest.fn(); - render( - -

Modal content

-
- ); + expect( onMouseEnterMock ).toHaveBeenCalledTimes( 1 ); + expect( onMouseLeaveMock ).toHaveBeenCalledTimes( 1 ); - expectTooltipToBeHidden(); + // Advance time again, so that we reach the full TOOLTIP_DELAY time + await sleep( HOVER_OUTSIDE_ANTICIPATION ); - const closeButton = screen.getByRole( 'button', { - name: /close/i, + // Tooltip won't show, since the mouse has left the tooltip anchor + expectTooltipToBeHidden(); } ); + } ); + + describe( 'shortcut', () => { + it( 'should show the shortcut in the tooltip when a string is passed as the shortcut', async () => { + render( ); - // Hover over the anchor, tooltip should show - await hover( closeButton ); - await waitFor( () => + // Hover over the anchor, tooltip should show + await hover( + screen.getByRole( 'button', { name: 'Tooltip anchor' } ) + ); expect( - screen.getByRole( 'tooltip', { name: /close/i } ) - ).toBeVisible() - ); + screen.getByRole( 'tooltip', { + name: 'tooltip text shortcut text', + } ) + ).toBeVisible(); + + // Hover outside of the anchor, tooltip should hide + await hoverOutside(); + await waitForTooltipToHide(); + } ); - // Press the Escape key, Modal should request to be closed - await press.Escape(); - expect( onRequestClose ).toHaveBeenCalled(); + it( 'should show the shortcut in the tooltip when an object is passed as the shortcut', async () => { + render( + + ); + + // Hover over the anchor, tooltip should show + await hover( + screen.getByRole( 'button', { name: 'Tooltip anchor' } ) + ); + const tooltip = screen.getByRole( 'tooltip', { + name: 'tooltip text Control + Shift + Comma', + } ); + expect( tooltip ).toBeVisible(); + expect( tooltip ).toHaveTextContent( /⇧⌘,/i ); + + // Hover outside of the anchor, tooltip should hide + await hoverOutside(); + await waitForTooltipToHide(); + } ); + } ); - // Hover outside of the anchor, tooltip should hide - await hoverOutside(); - await waitForTooltipToHide(); + describe( 'event propagation', () => { + it( 'should close the parent dialog component when pressing the Escape key while the tooltip is visible', async () => { + const onRequestClose = jest.fn(); + render( + +

Modal content

+
+ ); + + expectTooltipToBeHidden(); + + const closeButton = screen.getByRole( 'button', { + name: /close/i, + } ); + + // Hover over the anchor, tooltip should show + await hover( closeButton ); + await waitFor( () => + expect( + screen.getByRole( 'tooltip', { name: /close/i } ) + ).toBeVisible() + ); + + // Press the Escape key, Modal should request to be closed + await press.Escape(); + expect( onRequestClose ).toHaveBeenCalled(); + + // Hover outside of the anchor, tooltip should hide + await hoverOutside(); + await waitForTooltipToHide(); + } ); } ); } );