From 89e2371e594d435707f3aa31e6cfb5c9971f0cfc Mon Sep 17 00:00:00 2001 From: real-venus Date: Mon, 29 Jun 2026 02:49:32 -0700 Subject: [PATCH 1/2] test(components): cover Tooltip hover/focus/Escape behaviour Lock down the WCAG 2.1 SC 1.4.13 contract documented in Tooltip.tsx: - tooltip (role="tooltip") appears on mouse enter and on focus, and disappears on mouse leave and blur - stays visible while the pointer travels from the trigger onto the tooltip (hoverable) - aria-describedby on the trigger is present only while visible and points at the tooltip id, and is cleared again on hide - Escape hides the tooltip and leaves focus on the trigger (document.activeElement), while non-Escape keys are ignored - edge cases: rapid enter/leave/enter, and focus -> Escape -> re-show - collision-aware positioning: default-above, flip-below, and left/right viewport clamping 100% statements/functions/lines and 95.83% branch coverage of Tooltip.tsx. --- src/components/__tests__/Tooltip.test.tsx | 302 ++++++++++++---------- 1 file changed, 166 insertions(+), 136 deletions(-) diff --git a/src/components/__tests__/Tooltip.test.tsx b/src/components/__tests__/Tooltip.test.tsx index a7b1290..72cc7ce 100644 --- a/src/components/__tests__/Tooltip.test.tsx +++ b/src/components/__tests__/Tooltip.test.tsx @@ -1,6 +1,22 @@ import { act, fireEvent, render, screen, waitFor } from "@testing-library/react"; import { Tooltip } from "../Tooltip"; +/** + * Locks down the WCAG 2.1 SC 1.4.13 (Content on Hover or Focus) contract that + * Tooltip.tsx documents: show on hover/focus, stay hoverable, link the trigger + * via aria-describedby only while visible, and dismiss on Escape without moving + * focus. + * + * DOM shape rendered by Tooltip: + * span.wrapper ← owns the hover/focus/keydown handlers + * └ span[aria-describedby?] ← trigger's direct parent + * └ {children} ← the focusable trigger + * └ span[role="tooltip"] ← only mounted while visible + * + * Event note: React 19 listens for focus/blur via focusin/focusout and for + * mouseenter/mouseleave via mouseover/mouseout, so the tests fire those native + * events. A real .focus() is used where document.activeElement matters. + */ const renderTooltip = () => render( @@ -8,103 +24,153 @@ const renderTooltip = () => ); -// DOM shape: wrapper > [ describedBy-span >