Tooltip hover bug fix – test added and changelog updated

shoelace-style/webawesome

この PR は、ツールチップが HTML コンテンツ上で誤って閉じてしまうバグに対し、回帰テストを追加し、変更内容を CHANGELOG に記録したものです。

背景

<wa-tooltip>handleMouseOutthis.anchor?.matches(':hover')this.matches(':hover') に依存していたため、マウスポインタがホスト要素からスロット内子要素へ移動する際に :hover が偽になるケースがありました。この挙動は #2507 として報告され、#2512 で根本的に修正されました。PR #2516 は、その修正が正しく機能することをテストで保証し、リリースノートに反映させることを目的としています。

技術的な変更

CHANGELOG の更新

packages/webawesome/docs/docs/resources/changelog.md に、次のエントリが追加されました。

- Fixed a bug in `<wa-tooltip>` that caused the tooltip to hide when hovering over HTML content [pr:2512]

この一行の追加により、公開パッケージの変更履歴にバグ修正が明示され、利用者はアップデートの理由を容易に把握できます。

テストコードの拡充

テストファイル tooltip.test.ts で主に 2 か所が変更されています。

@@ -4,7 +4,7 @@ import { html } from 'lit';
 import sinon from 'sinon';
 import { expectEvent } from '../../internal/test/expect-event.js';
 import { fixtures } from '../../internal/test/fixture.js';
-import { clickOnElement } from '../../internal/test/pointer-utilities.js';
+import { clickOnElement, moveMouseOnElement } from '../../internal/test/pointer-utilities.js';
@@ -447,23 +447,32 @@ describe('<wa-tooltip>', () => {
         <wa-tooltip for="hover-child-btn" trigger="hover" show-delay="0" hide-delay="0">
-            <a href="#" id="tooltip-link">A link inside the tooltip</a>
+            <a href="#" id="tooltip-link" style="display: inline-block; padding: 1rem;">A link inside the tooltip</a>
           </wa-tooltip>
         </div>
       `);
       const tooltip = el.querySelector<WaTooltip>('wa-tooltip')!;
+      const anchor = el.querySelector<HTMLElement>('#hover-child-btn')!;
       const childLink = el.querySelector<HTMLElement>('#tooltip-link')!;

-      tooltip.open = true;
+      // Open the tooltip by hovering its anchor, so a real pointer is positioned over the trigger.
+      await moveMouseOnElement(anchor);
       await waitUntil(() => tooltip.open);
       expect(tooltip.open).to.be.true;

-      // Simulate the pointer moving off of the tooltip host and onto a slotted child element.
-      // relatedTarget is the element the pointer is moving to, which is how browsers report this.
-      tooltip.dispatchEvent(new MouseEvent('mouseout', { relatedTarget: childLink, bubbles: true }));
-      await aTimeout(50);
+      // Move the pointer off the anchor and onto a slotted child element of the tooltip. This generates a real
+      // `mouseout` whose `relatedTarget` is the slotted child, which the tooltip should recognize as "still within me"
+      // and stay open.
+      await moveMouseOnElement(childLink);
+      await aTimeout(tooltip.hideDelay + 50);

       expect(tooltip.open).to.be.true;
+
+      // Move the pointer fully away and confirm it now hides, proving the test isn't a false positive.
+      await moveMouseOnElement(document.body, 'top', 0, 0);
+      await waitUntil(() => !tooltip.open);
+      expect(tooltip.open).to.be.false;
     });
   });

moveMouseOnElement を利用することで、実ブラウザの mouseout が持つ relatedTarget を自然に取得でき、handleMouseOut の新ロジックが期待通りに動作することを検証しています。

設計判断

テストで synthetic MouseEventrelatedTarget を設定できないことが判明したため、実際のポインタ移動をシミュレートするユーティリティ moveMouseOnElement を採用しました。この選択は、テストがブラウザ固有のマウスイベント挙動を忠実に再現できるようにし、回帰テストの信頼性を高める設計判断といえます。また、CHANGELOG へのエントリはシンプルな箇条書きで追加することで、リリースノートの一貫性と可読性を維持しています。

まとめ

PR #2516 は、ツールチップの hover バグ修正を 自動テストで保証 し、CHANGELOG に記録 することで、品質と公開情報の両面でプロダクトの信頼性を向上させます。テスト実装に実際のポインタ操作を組み込む判断は、ブラウザ挙動の正確な検証を可能にし、将来的な UI 変更に対する回帰テストの有効性を高めています。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
41d50c5d

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
2回 (改善を経て承認)
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文、背景、技術的な変更、設計判断(任意)、まとめの5要素が揃っており、総論→各論→結論の流れが明確です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは言語指定のみでファイル名は不要なため問題なし。GitHubリンクは全て短縮PR/Issue番号形式で正しくリンク化されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

専門エンジニア向けの記述で、余計な初心者向け説明はなく適切です。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論・各論・結論の段落構成で、段落はトピックセンテンスで始まり、1段落1トピック、長さも適切です。空行で区切られています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のdiffブロックは提供されたPRのdiffと完全に一致し、ファイル名・変更箇所が正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

handleMouseOut、relatedTarget、moveMouseOnElement などの用語はPRで使用されているものと一致し、誤用はありません。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的な主張はPRの説明・diffで裏付けられ、因果関係も論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事の全ての事実はPR情報(タイトル、説明、diff)に基づき、推測や捏造はありません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号・Issue番号・ファイルパスなど数値情報は正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルはPR「Update test and changelog」の内容を過不足なく表現しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

バージョンサポートやリリーススケジュール等、PRに無関係な外部知識は含まれていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現は使用されておらず、PRの表現と齟齬はありません。