【JavaScript/Node.js】Playwrightの自動テスト記述におけるよく使う要素選択方法についてまとめてみた
はじめに
はじめまして。 SHIFT DAAE(ダーエ)テクノロジーグループの菊地です。
2023年11月15日更新の当ブログ内PV数ランキング で、以下の2つの記事がランクインしておりPlaywrightの需要の高さがうかがえます。本稿では、Playwrightにおけるロケータの推奨されている取得方法について、実際の業務で使用した経験などを踏まえ解説します。
【非エンジニア向け】テスト自動化ツールPlaywrightの使い方 :2023年8月23日更新 Playwrightの導入や、コードの自動生成について知りたい方はこちらを参照ください。
PlayWrightのすゝめ :2021年8月25日更新 Playwrightの特長についての、概ね3年前の記事です。 ロケータの取得方法等で紹介されている、page.$は非推奨機能になっています 。おすすめの方法がありますので、本記事にて紹介します。
環境
今回の記事で想定している環境は以下の通りです。 Google Chrome DevToolの試験運用機能を使用しますので、バージョンによっては、機能の導入方法が異なる可能性があります。
Node.js: 18.19.0
Playwright: 1.40.1
Google Chrome 120.0.x
要素の選択方法
公式のドキュメントのQuickGuide に記述がありますが、以下のような要素選択が推奨されています。
page.getByRole()
page.getByText()
page.getByLabel()
page.getByPlaceholder()
page.getByAltText()
page.getByTitle()
page.getByTestId()
これ以外にも、CSSやXPathでの要素取得(page.locator())でも要素は取得可能です。
getByRole()
一番使用頻度の高い取得方法です。画面の要素が持つ役割と、その名称で選択します。
例: "Sign Up"と書かれた見出し(例:<h2>)が存在することを確認する場合
await expect(page.getByRole('heading', { name: 'Sign up' })).toBeVisible();
のように第一引数にその要素の役割(Role)を、第二引数に任意でオプションを記述します。 今回はh2のRoleは'heading'のため、第一引数に'heading'、第二引数のオプションに、name: "Sign up"と指定しています。
第一引数で指定するRoleですが、WAI-ARIAという規格で、<h2>に'heading'が対応するように、htmlのタグとは名称が異なるものが指定されることがあります。 そのため、テキストで表示する内容と同じnameは問題なくとも、Roleに何を入れるか迷うことがあるかもしれません。 そのため、Roleに何を設定すべきかについてこれから紹介します。
Role/name判別のためのオススメ開発者ツール設定
Chromeの開発者ツールで、Roleを瞬時に判別できる設定を紹介します。
Ctrl + Shift + Iで開発者ツールを開きます。
右上の歯車アイコンをクリックし、DevToolの設定を開きます。
試験運用版内タブをクリックし、その中の"Enable full accessibility tree view in the Elements panel"にチェックを入れます。
4. 右上の×印を押下し、DevToolの設定を閉じます。
5. DevToolを再読み込みします。
6. DevToolsのコンソール タブに移動すると、右上に人型のマーク(アクセシビリティのマーク)が出るようになるので、これをクリックします。
以上の操作を行うと、ユーザ補助ツリーという、Roleとnameが表示される画面になります。
三角のすぐ右側にある赤文字部分がRoleで、その右に続く""で囲まれた青文字がnameです。そのさらに右にフォーカス可能かなどの状態が表示されます。
もう一度人型のマークをクリックすると、元のHTMLの表示に戻ります。 基本的には、この表示をもとにpage.getByRole()を使用していきます。
Roleから絞り込むnameの手動追加(aria-label)
先ほどの手順で、getByRole()で第一引数として使用するRoleの方は判別できるようになりました。 第二引数のオブジェクトで使用するnameは、先述のユーザ補助ツリーで、Roleと共に記載されています。しかしながら、以下の画像のように、文字なしのボタン等においては、nameが自動で付与されないものがあります。
このように、アイコンのみを表示するボタンなどテキストを持たない要素については、nameが自動で追加されません。このような要素にnameを手動で追加する方法が、aria-label属性です。以下のようにaria-label属性を追加して記述すると、以下の画像のように、ユーザ補助ツリーのbuttonの部分にnameがついたものになります。
<button aria-label="検索">
<svg (省略)></svg>
</button>
aria-labelを付けると、button "検索"とツリーで表示される要素になるので、Playwrightでは、 page.getByRole( "button", { name: "検索" }) という形で取得できます。(検索ボタンが複数ある場合は、それぞれに何を検索するものか、aria-label等で判別できるようにしてください)
もちろん、テキストを持つ要素にも、aria-label属性を付与することもできます。例えば、何らかの理由で、"こちら"という文字などにリンクを張ったときに、aria-label属性で、それが何を意味するのかを補足する、といった使い方です。
このaria-label属性は、さきほどユーザ補助ツリーという話が出たように、アクセシブル関係のもので、具体的には、スクリーンリーダーでの読み上げの際に使用されるものです。一般に公開するなど、スクリーンリーダーが使用される可能性が想定されるWebサイトの場合には、スクリーンリーダー使用時に読み上げられておかしくない文字列になるように気を付ける必要があります。
ここまで長々とgetByRole()での取得方法について深堀りしました。次のパラグラフからは、他の要素の取得方法について説明していきます。
getByText()
要素に書いてある文字で取得します。 <div>,<span>,<p>といった、文字を表現するタグに対して使用します。ボタンやリンクには、ボタンやリンクといった役割(Role)があるので、getByRole()で取得することが推奨されています。
完全一致や、正規表現の使用も可能です。
page.getByText("完全一致", {exact: true})
人数を表示している文字列を正規表現で取得する例
page.getByText(/\d+人/)
私は基本的には上の2つと、この後紹介するpage.getByPlaceholder()を使用してテストコードを記述しています。
page.getByPlaceholder()
ラベルのない<input>タグに対して、Placeholderの文字列で指定します。 page.getByPlaceholder().fill()という形で使うことが多いです。
ここからは、使用頻度のあまり高くないものについて、どのようなときに使用したのか紹介します。
page.getByLabel()
フォームのフィールドなどの<input>タグを子に持つ<label>タグに対して、対応するラベルの文字で指定します。
page.getByAltText()
<img>や<area>タグといった画像タグに付与するalt属性の文字で要素を取得します。
ただし、画像でも、<svg>の場合は、alt属性がないので使用できません。私の場合は、aria-label属性を付与し、page.locator('[aria-label="付与したaria-label"]')という、属性で取得する形で取得しています。
page.getByTitle()
title属性で要素を取得します。
page.getByTestId()
data-testid属性で要素を取得します。data-testid属性が変わらない限りテストの変更が不要で、変更に対して強いですが、ユーザに見えるものではないので、E2Eテストでは不向きです。基本的には、page.getByRole()やpage.getByText()で対応することを考えたほうがよさそうです。
page.locator()
以上の7つのgetBy○○関数で取得できないときに使用します。 XpathやCSSでの指定もできます が、あまり推奨されてはいません。なぜなら、DOM構造に依存するため、機能的な変更が無い、些細な変更でテストの修正が必要になる可能性があるからです。特に、複雑なものは非推奨とされています。
私は現状、aria-label属性を付与したものの、nameが付与されておらず、page.getByRole()で取得できないものについてpage.locator('[aria-label="付与したaria-label"]')という形で取得しています。(data-testid属性を付与してgetByTestIdで取得した方がいいのかもしれません)
おわりに
今回は、Playwrightにおける、ロケータの推奨されている取得方法について説明しました。 Playwrightを使用し始めて日が浅い方や、これからPlaywrightでテストをしていきたい方が、業務や個人開発などで使うことになった際のお役に立てれば幸いです。 私自身もまだまだコードの記述中に発見が多いので、精進していきたいです。
\もっと身近にもっとリアルに!DAAE公式Twitter/
お問合せはお気軽に
SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/
SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/
SHIFTの導入事例
https://service.shiftinc.jp/case/
お役立ち資料はこちら
https://service.shiftinc.jp/resources/
SHIFTの採用情報はこちら
PHOTO:UnsplashのJoan Gamell