日別アーカイブ: 2026年1月28日

PlaywrightとARIA

今月のSoftwareDesignを読んでいて、Playwrightのところで出てきたARIA。
どういうものなのか勉強がてら調べてみた

ARIAとは何か

ARIAは、Webコンテンツをスクリーンリーダーなどの支援技術で正しく解釈できるようにするための仕様です。W3CのWAI(Web Accessibility Initiative)が策定しています。

なぜARIAが必要なのか

HTMLの標準要素には、ブラウザが自動的にアクセシビリティ情報を付与します。

<button>保存</button>
<!-- ブラウザは自動的に「ボタン、保存」と支援技術に伝える -->

しかし、リッチなUIを作ろうとすると<div><span>でカスタムコンポーネントを作ることがあります。

<div class="fancy-button" onclick="save()">保存</div>
<!-- 支援技術には単なるテキスト「保存」としか伝わらない -->

この<div>はボタンのように見えて動作しますが、スクリーンリーダーはそれがボタンであることを認識できません。ARIAはこのギャップを埋めるために生まれたそうです。

ARIAの3つの柱

ARIAは主に3つの概念で構成されています。

Role(役割) は、要素が何であるかを定義します。

<div role="button">保存</div>
<!-- 「これはボタンです」と支援技術に伝える -->

Property(プロパティ) は、要素の性質や関係性を定義します。

<input aria-label="検索キーワード">
<div aria-describedby="hint-text">...</div>

State(状態) は、要素の現在の状態を定義します。

<button aria-pressed="true">太字</button>
<div aria-expanded="false">メニュー</div>

PlaywrightがARIAを活用する理由

Playwrightでは、従来のCSSセレクタによる要素特定に代えて、ARIAのロールと名前による特定を推奨しています。

// CSSセレクタによる従来の方法
page.locator('button.submit-btn')

// ARIAロールと名前による方法
page.getByRole('button', { name: '送信' })

accessible nameとは

getByRoleの第2引数で指定する「name」は、accessible name(アクセシブルネーム) と呼ばれるものです。以下の優先順位で決定されます。

  1. aria-label属性(最優先)
  2. aria-labelledbyで参照された要素のテキスト
  3. 要素内のテキストコンテンツ
  4. title属性(フォールバック)
<!-- aria-labelが最優先 -->
<button aria-label="送信する">Submit</button>
<!-- accessible name: "送信する" -->

<!-- ボタン内のテキストも使われる -->
<button>送信</button>
<!-- accessible name: "送信" -->

inputの場合は関連付けられた<label>も考慮されます。

<label for="email">メールアドレス</label>
<input id="email" type="text">
<!-- このinputのaccessible name: "メールアドレス" -->

なぜこのアプローチが優れているのか

実装の変更に強い:クラス名やID変更の影響を受けにくくなります。CSSセレクタに依存したテストは、デザイン変更のたびに壊れがちです。

アクセシビリティの担保:テストが通るなら、スクリーンリーダーでも適切に認識されることが保証されます。

可読性が高い:テストコードが「何をしているか」が明確になります。button.submit-btnよりbutton { name: '送信' }の方が意図が伝わります。

同じ名前の要素が複数ある場合

実際のアプリケーションでは「削除」ボタンが複数行に存在する、といったケースがあります。

<tr><td>商品A</td><td><button>削除</button></td></tr>
<tr><td>商品B</td><td><button>削除</button></td></tr>

この場合、親要素で絞り込むことで対処できます。

// 親要素で絞り込んでからロケート
page.getByRole('row', { name: /商品A/ })
    .getByRole('button', { name: '削除' })

まとめ

こう見ると、ARIAベースのロケーターをやろうとすると、aria用のプロパティを使いたくなりそう。でも、そういうのを使わなくてできるだけ表現し、最終手段として使うようにとのこと。
しっかりアクセシビリティを意識したフロントエンド実装が必要という話なんだなと。

ARIAでテストが書きにくいと感じたら、それはそのUIのアクセシビリティに問題がある可能性を示唆していると。テスト自動化とアクセシビリティ改善を同時に進められる、この相乗効果こそがARIAベースのテスト戦略の本当の価値です。

参考リンク