Slide 1

Slide 1 text

アクセシビリティとE2Eテスト ypresto 2022/11/19 フロントエンドカンファレンス沖縄

Slide 2

Slide 2 text

yprestoのプロフィール エンジニア数名のBtoBスタートアップ (スパイスコード) に所属 なんでもやるエンジニア 専任デザイナーいないしFigmaもやったり 少人数スタートアップのエンジニアの視点で今日は話します

Slide 3

Slide 3 text

スクリーンリーダー使ったことありますか? macOSのVoiceOverは Ctrl+Command+ 電源ボタン3 回 で起動・終了 ようこそダイアログの 詳しい情報 ボタンでチュートリアル開始 (WindowsはNVDAを入れた方が良いらしいです) 動画デモ 参考: ユーザーは音声だけでWebサイトをどう使うのか? 弁護士ドットコム、アクセシビリティユーザー調査の結果を公開

Slide 4

Slide 4 text

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 + → / ← で要素の種類を選らんで、そのまま ↓ / ↑ を押すと順番に移動できる機能も便利そう。

Slide 5

Slide 5 text

WAI-ARIA Webアプリケーションのアクセシビリティを高めるための方法を定義した仕様。 ロール ARIAの仕様で定義されているものから選ぶ ランドマーク ( , , ...)、見出し (

, ...) フォーム要素 (含むボタン) グリッド、テーブル 例えば ← 暗黙的ロールが設定されるものは
プロパティ、ステートもある: 注: CSSとは無関係なので、 display: table とかはスクリーンリーダーでは認識されない

Slide 6

Slide 6 text

忘れてください (E2Eのために) ARIAを使えばアクセシビリティ上がると思っていた 調べれば調べるほど間違った使い方をしていることに気がつく悲しみ WAI-ARIA属性 (roleなど) を活用したE2Eテスト HTMLのセマンティクスを活用したE2Eテスト アクセシビリティはARIA属性の前に、まず標準のタグを正しく使うほうが良い ARIAはMUI、Polaris、Chakraのなどで、部品レベルではサポートされている 注: ARIA属性は、使っていいときと悪いときがあります: WAI-ARIAを学ぶときに整理しておきたいこと by ゆうてん

Slide 7

Slide 7 text

E2Eテスト コードでブラウザを動かして、Webアプリケーショ ンをテストする。 なぜIntegrationテストだけでは足りないか 送ったJSONの一部をAPIが取りこぼし消滅 ログイン後の遷移先URLが404 CSSのバグで課金ボタンが画面外に ユーザーやビジネスの視点でのテスト リスクが実装コスト勝つコワい場所はペイ リリース前の動作確認を一部自動化できる

Slide 8

Slide 8 text

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(' ログイン') セレクタに対する操作をする

Slide 9

Slide 9 text

セレクタをユーザー視点で書きたい Selenium時代、セレクタがすぐ壊れたりしてメンテが頓挫した。(class/idなど) → cy.get('.foobar').click() class名やDOM構造はユーザーから見えない実装詳細。 動作確認と同様に、表示されているテキストをセレクタにする 壊れにくい&修正も容易なのでは やってみた Cypressでの課題&解決 ARIA属性書かなくてもわりとできた 実装詳細: Testing Implementation Details by Kent C. Dodds

Slide 10

Slide 10 text

課題1 入力欄をラベルで取りたい
メールアドレス
cy.contains('.MuiTextField-root', ' メールアドレス') // 親要素を検索 .find('input') // 中に入ってる入力欄をとってくる .type('[email protected]') // キーボード操作 ↓ Testing Library を導入し、 に紐付いた要素をなんなく取得できた cy.findByLabelText(' メールアドレス').type('[email protected]')

Slide 11

Slide 11 text

課題2 同じラベルの要素が複数ある cy.contains(' テストラベル').should('be.visible') // 常にサイドバーがヒット ↓ HTML標準のランドマークで、本文部分のみをチェックする。 cy.get('main').contains(' テストラベル').should('be.visible')

Slide 12

Slide 12 text

課題3 key-valueのペアの表示内容をチェックしたい
製造日
2022/11/23
賞味期限
2023/11
cy.contains('div', ' 賞味期限') // ラベル要素とってきて .parent() // 親に移動して .should('contain.text', '2023/11') // 該当テキストがあるか ( かなり適当) 「行」に当たる
を取るのが難しい

Slide 13

Slide 13 text

課題3 ARIAの role="group" を乱用してしまった
製造日
2022/11/23
賞味期限
2023/11
cy.findByRole('group', { name: ' 賞味期限' }).should('contain.text', '2023/11')` E2Eしなかったら存在しなかった role="group" がいっぱいできてしまった。 本来、複数のinputをまとめたりするのに使う

Slide 14

Slide 14 text

課題3 標準の説明リストタグを使って解決
製造日
2022/11/23
賞味期限
2023/11
↓ cy.contains('dt', ' 賞味期限').next('dd').should('have.text', '2023/11') MDN:
: 説明リスト要素 の例 に例として載っていた ただしVoiceOverでは、 定義リスト4 項目 → 製造日 4 の1 → 2022/11/23 4 の2 → ... と読み上げられ、行ごとに扱える感じがなかった

Slide 15

Slide 15 text

ARIAがほしくなる例 アイコンボタン ... cy.findByRole('button', { name: ' 送信' }) cy.findByRole('dialog').within(() => { ... })
cy.findByRole('toolbar') (Testing Library)

ブログ1

...

Slide 16

Slide 16 text

ARIA DevTools かんたんな確認用に。

Slide 17

Slide 17 text

まとめ E2Eはビジネスを止めないために投資する MUI、Polaris、Chakraなど、WAI-ARIAがサポートされてるライブラリを使う フォーム要素、ランドマーク、見出しを含め、標準のタグを有効に活用する アイコンボタンだけは aria-label="..." をつける するとE2E捗る Testing Library便利

Slide 18

Slide 18 text

参考資料 ユーザーは音声だけでWebサイトをどう使うのか? 弁護士ドットコム、アクセシビリテ ィユーザー調査の結果を公開 WAI-ARIAを学ぶときに整理しておきたいこと by ゆうてん Webフロントエンドのリプレースを支えるテストの考え方 by berlysia WAI-ARIA Authoring Practices Guide (APG)