【輪読会レポート】[入門]Webフロントエンド E2E テスト PlaywrightによるWebアプリの自動テストから良いテストの書き方まで 第3章「Playwrightのテスト用ツールセット(1)ロケーター」
はじめに
こんにちは。ラクス フロントエンドチームのたぐちです。
今回は輪読会の実施レポートvol.1です。
書籍と読書範囲
今回の読書範囲は第3章 Playwrightのテスト用ツールセット(1)ロケーターのP41~P62です。
議論・意見交換
付箋の内容を左上から順に読んで議論していきました。実際の議論順で内容を確認していきます。
getByLabel()でラベルからInput要素を探す
「getByLabel() ってラベルだけ取得するものだと思ってた…」
そんな声が上がった今回の輪読会。
getByLabel() は、ラベルに紐づいたinput要素も取得できるのですが、aria-label を使って getByRole() で要素を取得することが多い場合、getByLabel() の真価に気づきにくいのかもしれません。
ロケーターgetByRole(button)でボタン要素全て取ってきてbutton[1]のようにインデックスで取得してたの後悔している。nth(2)とか
E2Eテストでやりがちなのが、getByRole('button')[1] のようにインデックスを使って要素を取得する方法。
しかし、これは画面修正の影響を受けやすく、壊れやすいテストの元凶になりかねません。
要素は filter などで絞り込む方が、堅牢なテストを構築できます。
3.3 壊れやすいテストの話的に、スナップショットテストは壊れやすそう?
DOM構造やクラス名はリファクタリングの影響を受けやすいため、スナップショットテストは壊れやすいという意見が出ました。
一方で、「想定通りの変化」 を確認するためのスナップショットテストにおいて、それが確認できれば問題ないという意見も。
getByAltText(), getByTitle()あたりは使ったこと無いなあ...(HTMLに不誠実)
getByAltText や getByTitle を使ったことがないメンバーが多数。
これらの情報はホワイトボックステストになりがちで、E2Eテストでは避けたいという意見が出ていました。
目に見える要素を使ってテストを書くべき(getbytestIdなどは最終手段)
E2Eテストは、ユーザー視点のブラックボックステストで書くべき。
data-testid などの内部実装に依存したテストは最終手段と心得ましょう。
一瞬表示されるようなツールチップがロケーターで取れずに諦めてた。jest, VueTestingLibrary
ホバーで表示されるツールチップなどは、ロケーターで取得するのが難しいという意見が出ました。
3.4.1 input type="image"はroleがbuttonになるの知らなかった
input type="image" を使ったことがないメンバーも多く、これが role="button" になることを初めて知ったという声も。
割とdivタグの拡張コンポーネントにdata-testid付けちゃう
data-testid を直接指定するのは避けるべきですが、カードなどのコンポーネントを絞り込む際には有効という意見がありました。
特に、複数カードが存在する画面などでは、つい使ってしまうのも頷けます。
data-testidはなるべく使うべきでないがidやclassよりマシ
こちらもブラックボックステストでなくホワイトボックステストでテストを書くべきという意見でした。
ただ、単体テストレベルだとdata-testidを多用しがちという意見もありました。
filter楽しそう
filterを使った要素絞り込みの例を見て、「楽しそう」という感想が。楽しそう…?
確かに、filter を駆使すれば、柔軟なテストが実現できそうです。
3.4.1 selectのoptionのテスト書いたけど、あちらこちらのoptionにヒットしてめっちゃ書きづらかった記憶
role=option で要素を取得する際に、想定通りの絞り込みが難しかったという経験が共有されました。
3.3. 状態を指す場合に「コンポーネントの中の〇〇が△△」は確かにメンテつらそう(意識して実装する部分でもないから)
コンポーネントの状態を指定したテストは、メンテナンスが大変。
E2Eテストでは、ユーザー視点のシナリオを記述することが重要です。
ドメインエキスパート:利用者側のプロフェッショナル
「ドメインエキスパート」 という言葉を知っていますか?
ユーザー側のプロフェッショナルであるドメインエキスパートを意識することで、より分かりやすく、壊れにくいテストを作成することができます。
.click()を連発して、他の人がテスト見た時に何しているか分からないこと良くあった
E2Eテストでは click() を多用しがちですが、テストコードの可読性が低下するという問題点も。
3.5.3 table系はnthよく使いますね
table要素でつい nth を使ってしまうものの、壊れやすいテストになってしまうというジレンマを共有。table要素のテストは、慎重に進める必要がありそうです。
3.5. UIフレームワーク使ってるとhtmlForを上手く使える気がしない(一緒にしちゃうか、labelを諦めるかになりがち)
コンポーネントに id と htmlFor を設定するのが難しい、という意見が出ました。id被りを気にしたり、注意することが多いためですね。
UIフレームワークの仕様によっては、工夫が必要になるケースも多そうです。
has: ${ロケータ} は結構よく使う
子要素を持つ親要素にアクセスする際に便利なのが、has: ${ロケータ}。
PageObjectパターンで使うと、より効果を発揮します。
3.5. ...filter(...).filter(...).filter(...) みたいになることって無いんだろうか
要素の絞り込みに filter を多用すると、メソッドチェーンが発生する可能性が浮上しました。
可読性を維持できる範囲で利用したいよね、という意見でまとまりました。
filterで長々と書くんだったら、testIdを使いたい。
当初はそう考えていたものの、議論を通して、ユーザーが実際にアクセスできる要素で絞り込むことの重要性を再認識したそうです。
3.5. 全体的に、「テストをゴチャゴチャ書く前に綺麗なHTML書きましょうね」という考えが強い。E2Eだとテストファースト難しそう
「セマンティックHTML」を書けばE2Eテストも書きやすいという理想は理解できるものの、立ち上げの段階から意識して開発するのは現実的には難しいという意見が出ました。
かといって、後からの修正も難しいため、E2Eテストファーストは難しいと改めて実感しました。
まとめ
今回の輪読会レポートは以上です。深い議論が出来て参加したメンバー全員有意義に感じていました!
次回開催は07/09(火)の予定ですので、お楽しみに!
終わりに
ラクスでは、エンジニア・デザイナーの中途採用を積極的に行っています。ご興味ありましたら是非ご確認をお願いします。
採用情報
https://career-recruit.rakus.co.jp/engineer_jobs/frontend_tokyo/
https://career-recruit.rakus.co.jp/career_engineer/