mcpField
U
ui-data-testid

ui-data-testid

github.com/dtyqテスト・品質5.1k38 回インストール4 日前に更新
リポジトリ

ui-data-testid について

UI実装時に安定した `data-testid` を追加し、翻訳や見た目の変更に左右されにくいテストセレクターを整えるスキルです。命名、対象範囲、繰り返し行の特定、テストでの検索方法を示します。

主な機能

  1. 01ルートと操作要素へのID付与
  2. 02意味のあるkebab-case命名
  3. 03繰り返しリストへの行ID付与
  4. 04テストで安定したセレクターを優先
  5. 05既存IDの維持と非同期状態の網羅

活用シーン

  1. 01新しいフォームに安定したテストセレクターを追加
  2. 02既存IDを保ちながらメニューやダイアログを改修
  3. 03繰り返し行とその操作を特定してテスト

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dtyq/magic --skill ui-data-testid

インストール後、Claude Code で/ui-data-testidを入力して読み込まれたか確認します。

同梱ファイルagents/openai.yaml

詳細

UI の Data-testid

概要

後からパッチとして追加するのではなく、実装時に UI コードへ予測可能な data-testid 属性を追加してください。 i18n のテキスト変更やビジュアルリファクタリング後もセレクターが安定するようにしてください。 .cursor/rules にあるプロジェクトのテストルールに従ってください。

  • リファクタリングや移行時に既存の data-testid を維持する
  • プロジェクトのテストでは data-testid-first のクエリ戦略を使用する

ワークフロー

  1. 機能やモジュールのコンテキストからスコープのプレフィックスを決定します(例:user-menus、organization-switch、settings-profile)。
  2. コンポーネントのルートコンテナに data-testid を追加します。
  3. 主要なインタラクティブ要素すべてに data-testid を追加します。
    • ボタンやリンクのトリガー
    • input/select/checkbox/radio コントロール
    • タブ、メニュー項目、サブメニューのトリガー
    • モーダルやドロワーの起動操作と確定操作
  4. 設定駆動型 UI(例:menu.items)では、設定に "data-testid" を追加し、レンダラーやラッパーコンポーネントで実際にクリック可能な DOM ノードへ引き継ぎます。
  5. 繰り返し表示されるリストの行や項目では、まず行や項目のコンテナに安定した data-testid を設定します。原則として、子要素ごとに個別の一意な ID を追加しないでください。
  6. リストの行や項目内では、テストで行のスコープを再利用します。共有される行 ID とテキストや業務データで行を特定し、その後 within(row) またはロールやラベルのセレクターで子コントロールを検索します。
  7. 行のスコープ内で子要素を確実に選択できない場合に限り、繰り返し表示される行に子要素レベルの data-testid を追加します。必要な場合も、行 ID を付け足すのではなく、行をまたいで共有される子要素 ID を使用します。
  8. ユーザーから明示的に名前の変更を求められない限り、既存の ID は変更しないでください。移行タスクで既存の ID を削除してはいけません。
  9. インタラクションを変更する場合は、可能であれば同じ場所にある __tests__ に Vitest/RTL テストを追加または更新します。

命名規則

  • 小文字の kebab-case のみを使用します。
  • 意味のある形式を使用します:<scope>-<entity>-<action>。
  • ID はテキストに依存しないようにします(i18n ラベルに依存させないでください)。
  • 動的またはランダムな値(Date.now、UUID、翻訳されたテキスト)を避けます。
  • シークレット、メールアドレス、電話番号、トークンを含めないでください。
  • 該当する場合は、安定したサフィックスを使用します:trigger、content、button、input、option、item、row、loading、empty、error。

最低限のカバレッジチェックリスト

新しく作成する UI コンポーネントには、少なくとも以下を含めてください。

  • ルートコンテナのテスト ID を 1 つ
  • 主要な CTA のテスト ID を 1 つ
  • 各副次アクションボタンのテスト ID
  • 各フォームフィールドグループやコントロールのテスト ID
  • メニューがある場合は、各メニュー項目トリガーのテスト ID
  • 繰り返し表示されるリストやテーブルでは、リストコンテナ ID を 1 つ、行や項目のコンテナ ID を 1 つ。行スコープのセレクターでは不十分な場合を除き、セルやアクションごとに動的な ID を付けるのは避けます
  • 変更対象ファイルにおける過去からの data-testid の維持
  • 非同期 UI における loading/empty/error のテスト ID

クエリの優先順位

テストを作成または更新する場合:

  • このプロジェクトでは、安定したセレクターとして getByTestId を優先します
  • 補完的なアサーションには getByRole、getByLabelText、getByText を使用します
  • ユーザー向け動作テストでは、container.querySelector(...) セレクターを避けます

これにより、.cursor/rules/testing-guide.mdc との整合性を保てます。

シナリオ別プレイブック

要素を安定かつ正確に指定するには、次のパターンを適用してください。

  1. フォーム
    • フォームコンテナー、入力欄、送信/キャンセルボタン、バリデーションエラーに ID を追加します
  2. リストとテーブル
    • リストコンテナーと行コンテナーに ID を追加します
    • 共通の行 ID を優先し、その後テキスト/業務データで対象の行を選択します
    • 直接行を検索する具体的な必要がある場合に限り、行 ID の接尾辞に安定した業務キーを使用します
    • 行内の各フィールド/アクションに個別の動的 ID を追加しないでください。子アクションは within(row) スコープで検索します
    • 子アクションに data-testid が必要な場合は、collaborator-remove-button などの共通 ID を使用し、行スコープから検索します
  3. メニューとドロップダウン
    • トリガー、ポップアップの内容、各操作可能なメニュー項目に ID を追加します
    • メニューが設定駆動の場合は、項目レベルの data-testid をレンダリングされるノードに渡します
  4. モーダルとドロワー
    • 開くトリガー、モーダルの内容、主要アクション、閉じる/キャンセルアクションに ID を追加します
  5. 非同期状態
    • ローディング、空、エラーの各状態に ID を追加します

安定性のルール

  • 順序が変わる可能性がある場合、配列インデックスから ID を生成しないでください。
  • ランダム値やタイムスタンプから ID を生成しないでください。
  • ページ内で単一要素の ID が一意になるようにしてください。
  • 繰り返し表示されるコンポーネントでは、子要素に共通の ID を付け、within(...) でスコープを指定してください。
  • 繰り返し表示される行では、子要素単位の一意性より行単位の一意性を優先してください。行コンテナーでスコープを指定できない場合を除き、子要素の ID に行 ID を含めないでください。

パターン

コンポーネントのマークアップ
<div data-testid="user-menus-organization-info">
  <button type="button" data-testid="user-menus-upgrade-button" />
  <button type="button" data-testid="user-menus-recharge-button" />
</div>
繰り返し表示されるリストの行
<div data-testid="collaborator-list-content">
  {collaborators.map((collaborator) => (
    <div
      key={collaborator.id}
      data-testid="collaborator-item"
      data-collaborator-id={collaborator.id}
    >
      <span>{collaborator.name}</span>
      <button type="button" data-testid="collaborator-remove-button" />
    </div>
  ))}
</div>

const row = page
  .getByTestId("collaborator-list-content")
  .locator('[data-testid="collaborator-item"]')
  .filter({ hasText: receiverName })

await row.getByTestId("collaborator-remove-button").click()
設定とレンダラーへの引き継ぎ
const items = [
  { key: "logout", label: t("logout"), "data-testid": "user-menus-logout" },
]

<ItemComponent data-testid={menuItem["data-testid"]}>{menuItem.label}</ItemComponent>

完了条件

変更対象の UI ファイルにある新しい単一の操作可能なノードすべてに安定した data-testid 値が設定され、繰り返し表示されるリスト/テーブルの行に、行スコープから子コントロールを検索できる行レベルのセレクターが設定されている場合に限り、完了としてください。 移行/リファクタリングの差分で既存の data-testid が意図せず削除されていないことを確認してください。

コメント