Upgrade to Pro — share decks privately, control downloads, hide ads and more …

アクセシビリティとE2Eテスト

ypresto
November 19, 2022

 アクセシビリティとE2Eテスト

2022/11/19 フロントエンドカンファレンス沖縄での発表。

ユーザーの操作から実際のシステムまでを自動でテストするE2Eテストは、すでに動いているフロントエンドアプリの品質を担保しながら開発する際に欠かせないものと考えています。一方で、HTMLのクラス名でボタンや入力欄を指定したりすると、HTML構造を変更しただけでテストが壊れメンテが大変になります。 (テストから押すボタンにdata-属性をつけて回ることも提案されています)

一方で、HTMLにはアクセシビリティのためのWAI-ARIA規格があり、スクリーンリーダーのために必要なメタデータを記述できます。
ここでスクリーンリーダーとは人間のための機械であり、機械で処理しやすいということは、E2Eテストでも利用しやすいということになります。
これを実践してみての知見を話します。

https://fortee.jp/fec-okinawa-2022/proposal/ac6ea377-1260-4639-9e27-406917b2b001

ypresto

November 19, 2022
Tweet

More Decks by ypresto

Other Decks in Programming

Transcript

  1. VoiceOverの使い方 ( VO = Ctrl + Option + ) 要素単位で移動する

    VO + Shift + 右 / VO + Shift + 左 グループやテーブルなどの中に入る・出る VO + Shift + 下 / VO + Shift + 上 グループの中に入らず移動する VO + Shift + 右 / VO + Shift + 左 ローター VO + U (困ったらこれを押すと良さそう) 右 / 左 で ランドマーク / 見出し / リンク / フォームコントロール を選んで 上 / 下 で項目の選択 Esc で閉じる 設定 VO + Command + Shift を押しながら 左右 で選択 / 上下 で変更 一覧: macOS版VoiceOverの初歩的な使い方をまとめてみた (dev.classmethod.jp) VO + Comamnd + → / ← で要素の種類を選らんで、そのまま ↓ / ↑ を押すと順番に移動できる機能も便利そう。
  2. WAI-ARIA Webアプリケーションのアクセシビリティを高めるための方法を定義した仕様。 ロール ARIAの仕様で定義されているものから選ぶ ランドマーク ( <nav> , <main> ,

    ...)、見出し ( <h1> , ...) フォーム要素 (含むボタン) グリッド、テーブル 例えば <button> ← 暗黙的ロールが設定されるものは <div role="toolbar"> プロパティ、ステートもある: <button aria-expanded="true"> 注: CSSとは無関係なので、 display: table とかはスクリーンリーダーでは認識されない
  3. Cypressの例で見るE2E ログインフォームが成功するのをチェックする例 cy.get('.email').type('[email protected]') // メアドの入力 cy.get('.password').type('fake password') // パスワードの入力 cy.contains('

    ログイン').click() // ログインと書かれた要素を探してクリック cy.get('h1', ' マイページ').should('be.visible') // h1 のタイトルを確認 セレクタで要素を取る CSSセレクタ .get('.email') テキストでのセレクタ .contains(' ログイン') セレクタに対する操作をする
  4. 課題1 入力欄をラベルで取りたい <div class="MuiTextField-root"> <label for="input-prefecture"> メールアドレス</label> <input id="input-prefecture"> </div>

    cy.contains('.MuiTextField-root', ' メールアドレス') // 親要素を検索 .find('input') // 中に入ってる入力欄をとってくる .type('[email protected]') // キーボード操作 ↓ Testing Library を導入し、 <label> に紐付いた要素をなんなく取得できた cy.findByLabelText(' メールアドレス').type('[email protected]')
  5. 課題3 key-valueのペアの表示内容をチェックしたい <div> <div> <div> 製造日</div><div>2022/11/23</div> </div> <div> <div> 賞味期限</div><div>2023/11</div>

    </div> </div> cy.contains('div', ' 賞味期限') // ラベル要素とってきて .parent() // 親に移動して .should('contain.text', '2023/11') // 該当テキストがあるか ( かなり適当) 「行」に当たる <div> を取るのが難しい
  6. 課題3 ARIAの role="group" を乱用してしまった <div> <div role="group" aria-labelledby="..."> <div id="...">

    製造日</div><div>2022/11/23</div> </div> <div role="group" aria-labelledby="expiration"> <div id="expiration"> 賞味期限</div><div>2023/11</div> </div> </div> cy.findByRole('group', { name: ' 賞味期限' }).should('contain.text', '2023/11')` E2Eしなかったら存在しなかった role="group" がいっぱいできてしまった。 本来、複数のinputをまとめたりするのに使う
  7. 課題3 標準の説明リストタグを使って解決 <dl> <div> <dt> 製造日</dt><dd>2022/11/23</dd> </div> <div> <dt> 賞味期限</dt><dd>2023/11</dd>

    </div> </dl> ↓ cy.contains('dt', ' 賞味期限').next('dd').should('have.text', '2023/11') MDN: <dl> : 説明リスト要素 の例 に例として載っていた ただしVoiceOverでは、 定義リスト4 項目 → 製造日 4 の1 → 2022/11/23 4 の2 → ... と読み上げられ、行ごとに扱える感じがなかった
  8. ARIAがほしくなる例 アイコンボタン <button aria-label=" 送信"><svg>...</svg></button> cy.findByRole('button', { name: ' 送信'

    }) cy.findByRole('dialog').within(() => { ... }) <div role="toolbar"> cy.findByRole('toolbar') (Testing Library) <article aria-labelledby="blog1"> <h3 id="blog1"> ブログ1</h3> ... </article>