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

VoiceOverの自動テスト

grgr-dkrk
August 30, 2022

 VoiceOverの自動テスト

1
それでは「VoiceOverの自動テスト」というテーマで発表させていただきます。よろしくお願いいたします。

2
わたくしぐるぐるできること申します。久しぶりのLTです。10月に入籍する予定でバタバタしてます。
最近はAWS CDK という、AWS を TypeScript でプロビジョニングする闇のライブラリに悪い意味でハマっています。
埼玉県というか、ヤオコーという埼玉のスーパーが大好きでずっと住んでます。あと千鳥という芸人がいるんですけども、この千鳥が関東に進出する時、初めて持ったテレビ番組が「いろはに千鳥」というテレ玉の番組でして、いつも埼玉でロケしてたんで、彼らは埼玉の芸人であると勝手に思っています。

3
今回 VoiceOver の操作を自動化するんですけども、この VoiceOver というのは macOS や iOS で使えるスクリーンリーダーというものです。
スクリーンリーダーというのはカーソルを合わせて、画面上の要素を読み上げたり、操作できたりするものですね。
これの直接的な自動テスト自体は難しいのですが AppleScript で動かせる、というのが今回のテーマとなります。

4
AppleScript というのは 1993 年からある Apple のスクリプト言語でして、これを使うと Mac OS の操作を自動化することができます。
今回はこれで VoiceOver 動かせばテストできるよという話ですね。

5
この AppleScript なんですけれども、VoiceOver に関するリファレンスがないのですが、Mac に最初から入っているスクリプトエディタ.app に VoiceOver の app ファイルを突っ込むと ドキュメントが出てくるようになっていますので、これを見て使えるコマンドとかを調べます。

6
あとは勘でスクリプトを書いていきます。VoiceOver を Node のコマンドでラップしてるだけです。
AppleScript は自然言語のように書けるのも特徴となっていますが、具体的な文法は省略します。

7
あとはこれを CI 上とかで動かせるようにする必要があります。実は VoiceOver を AppleScprit で動かすには VoiceOverユーティリティという設定アプリで AppleScript を有効にしないといけないので、設定をターミナルで再現します。
また、VoiceOver の初回起動時はトレーニング画面が開くようになっているので、そちらも無効化します。
これでテストの準備ができます。

7
今回のテスト対象としては、VoiceOverを立ち上げて、HTML 上の見出しを読み上げてくれるか、img要素のalt属性の内容を読み上げるかをテストします。
あとは、「今日の占い」というボタンを押すとその後の「工事中のコンテンツです」という文言が変化するようになっていますが、この文言の親要素にはaria-live属性というのがありまして、子要素のコンテンツが変化した時にスクリーンリーダーが変化後のコンテンツを読み上げようになっています。今回はVoiceOver での実際の挙動もテストしてみます。

8
実際にテストケースを書きます。今回はプレイライトに入れただけなんですけど、プレイライトの機能と連携できるわけではないので、ブラウザが立ち上がればなんでもいいと思います。
実際にテストしますと、ブラウザが開いて、ちょっと速いんですけどもスクリーンリーダーが開きまして、読み上げやボタンの操作だったり、aria-liveとの連動などを自動テストできているというのがわかります。
(動いているところのGIF: https://www.dkrk-blog.net/gifs/a11ytest.gif

9
ちょっと乱暴な形のテストにはなるのですが、今回のようなアプローチの JavaScript ライブラリーが他にもありますので参考にしてみてください。
最近だと guidepup が本格的でトレンドなのかな、とも思いますがドキュメントが少なくこれからという段階です。

10
以上です。ありがとうございました。

grgr-dkrk

August 30, 2022
Tweet

More Decks by grgr-dkrk

Other Decks in Programming

Transcript

  1. צͰॻ͘ # VoiceOver Λىಈ͢Δʢ͜Εʹ֘౰͢ΔεΫϦϓτ͕ͳ͔ͬͨʣ execSync('/System/Library/CoreServices/VoiceOver.app/Contents/MacOS/VoiceOverStarter') # ΧʔιϧΛ࠷ॳͷཁૉʹҠಈ͢Δ execSync('osascript -e \'tell

    application "VoiceOver" to tell vo cursor to move to first item\'') # ࠷ޙʹ஻ͬͨϑϨʔζΛग़ྗ͢Δ execSync('osascript -e \'tell application "VoiceOver" to return content of last phrase\'')
  2. $*Ͱಈ͘Α͏ʹ͢Δ # AppleScript Ͱ VoiceOver Λ੍ޚͰ͖ΔΑ͏ʹ͢Δᶃ defaults write com.apple.VoiceOver4/default SCREnableAppleScript

    -bool true # AppleScript Ͱ VoiceOver Λ੍ޚͰ͖ΔΑ͏ʹ͢Δᶄ sudo bash -c 'echo -n "a" > /private/var/db/Accessibility/.VoiceOverAppleScriptEnabled’ # VoiceOver ॳىಈ࣌ͷτϨʔχϯάը໘Λແޮʹ͢Δ defaults write com.apple.VoiceOverTraining doNotShowSplashScreen -bool true # ※GitHub Actions ͷ macOS Πϝʔδ͸σϑΥϧτͰ্هΛαϙʔτ͍ͯ͠Δ…͸͕ͣͩಈ͔ͳ͔ͬͨ # https://github.com/actions/runner-images/issues/4770 # .VoiceOverAppleScriptEnabled ͷμϛʔ࡞੒͕ݖݶతʹΩπ͍ɻactions/guidepup-setup Λ࢖͏ # https://github.com/marketplace/actions/guidepup-setup
  3. ࠓճͷςετର৅ <body> <h1>ࢲͷϗʔϜϖʔδ΁Α͏ͦ͜</h1> <!-- ݟग़͠ΛಡΈ্͛Δ --> <img src="./baby_music_piano_boy.png" alt="੺ͪΌΜ͕࠲ͬͯসإͰϐΞχΧΛ஄͍ͯΔ" />

    <!-- alt ΛಡΈ্͛Δ --> <button id="js-button">ࠓ೔ͷ઎͍</button> <div aria-atomic="true" aria-live="assertive"> <p id="js-result">޻ࣄதͷίϯςϯπͰ͢ɻ</p> <!-- ͜͜ͷίϯςϯπ͕มΘΔͱɺεΫϦʔϯϦʔμʔ͕ࣗಈͰಡΈ্͛Δ --> </div> <script> document.addEventListener('DOMContentLoaded', function () { document .getElementById('js-button') .addEventListener('click', function () { document.getElementById('js-result').innerText = 'ΤϥʔͰ͢' }) }) </script> </body>