超入り口Playwright解説&落とし穴備忘録【初心者向け】
初めまして、クラウドソリューショングループの新人、satokです。
今回は私が現場で初めて触った、テスト自動化フレームワークのPlaywrightについて、
私なりの初心者向けの解説と私が嵌った落とし穴の共有をさせていただきます。
目次
1. この記事の目的
この記事はPlaywrightが何か知らない初心者を対象に、Playwrightがどういうものかを簡単に解説しつつ、新人エンジニアである私がPlaywrightを触ってみて嵌った落とし穴について共有したいと思います。この記事を通してPlaywrightや自動化に興味を持ち、皆様の業務効率改善に繋がればと思います。
2. Playwrightとは
任意のブラウザ、任意のプラットフォームで用いることができる、エンドツーエンドのテスト自動化フレームワークです。(公式ドキュメントより)
簡単に言うとwebアプリケーションでのテストを自動化するためのツールです。
インストール方法などは公式ドキュメントや他のブログでもたくさん紹介されているため、今回は割愛します。
3. 何ができるのか
定義的な紹介はさておき、実際にPlaywrightでどんなことができるか見ていきましょう。
今回はWindows10、VSCode1.82.0、Node.js 16.20.1の環境で行います。言語はTypeScriptを使います。
エンドツーエンドのテストを行うために、まずは適当なwebページにアクセスしてみましょう。
今回はサンプルとして弊社の製品紹介のページに飛んでみます。
ファイル名: test.spec.ts
import { test } from '@playwright/test';
test('アイソルート: 製品・サービス紹介画面', async ({ page }) => {
await page.goto("https://www.isoroot.jp/business/");
});
この部分からテストを実行してみます。
無事にページを開くことができました。
次に、そのページを閉じずに、VSCode上の左下に出るPick locatorを押してみます。
そうすると、先ほどの製品紹介のページで、ページ内の要素にカーソルを合わせると青色の枠とともに文字が表示されます。
これらはPlaywright側からページ内の要素を特定するための名前のようなもので、コード側でこれらを指定することで様々な操作が行えます。
では、カーソルを適当なサービスに合わせて、クリックしてみます。
クリックしてもページ側では特に何も起こりません。Pick locator中は、要素をクリックしてもリンクを踏んだりすることはできませんが、VSCodeに戻るとクリックした要素が記録されます。
これをコピーしてコード側に張り付けることで、ページ内の好きな要素に対してアクションすることができるわけです。公式ドキュメントでは”アクション”は”アサーション,Assertions”と呼ばれています。
では、先ほど選んだサービスについて、Playwrightから”表示されているかのテスト”をしてみましょう。(まぁ見えているものを選んでいるので表示されているのは当たり前ですが……)
Playwrightでは、何かテストを行う際にexpect()を使います。今回は表示されているかどうかなので、先ほど選んだ要素について、toBeVisibleかどうかをテストします。
import { expect, test } from '@playwright/test';
test('アイソルート: 製品・サービス紹介画面', async ({ page }) => {
await page.goto("https://www.isoroot.jp/business/");
await expect(page.locator('span').filter({ hasText: 'SmartGEMBA巡回点検ソリューション' }))
.toBeVisible();
});
実行し、VSCode上で緑のチェックアイコンが出ていればテストが無事成功したことが確認できます。
また、テスト実行後に、テストを行っているフォルダの中のplaywright-reportフォルダにindex.htmlファイルが生成されます。この中身にもテストの実行結果が表示されるため、どこでエラーしたか、どれくらい時間がかかったかなどを見たい場合はこちらをチェックするようにしましょう。
さて、無事にテストが完了しましたが、無事に完了しなかった場合も見てみましょう。
先ほどの要素について、適当に文字を付け加えて、存在しない要素を指定してみましょう。
import { expect, test } from '@playwright/test';
test('アイソルート: 製品・サービス紹介画面', async ({ page }) => {
await page.goto("https://www.isoroot.jp/business/");
await expect(page.locator('span').filter({ hasText: 'hogeSmartGEMBA巡回点検ソリューション' }))
.toBeVisible();
});
これで実行すると、エラーを吐かれます。VSCode上にもエラーの内容が出力されますが、せっかくなので先ほど紹介したplaywright-report配下のindex.htmlを見てみましょう。
エラー内容を要約すると”5秒間探してみたけどそんな要素はないよ”というものです。(この”5秒間”というところはconfigなどで変更することができますが、今回は割愛します。)
この後別の部分でこのコードはまだ使うため、hogeは一旦消しておいてください。
このように、Playwrightでは、要素が表示されているか、などのテストを”一定時間内に達成できるか”でテストしています。この他にも、ここでは扱いませんでしたが、表示以外にも、”ラジオボタンがチェックされているか”や”テキストボックスに文字を入力する”や”マウスカーソルを移動させる”などのテストに必要な操作をほとんど自動化させることができます。
ここで紹介した内容は全体でできることのほんの一部ですので、もっと詳しく知りたい方は公式ドキュメントをチェックしてみてください!
4. 初心者向け落とし穴
さて、ここで”Playwrightでテスト自動化ライフを満喫しましょう”で終わっても良いのですが、今回のメインはここからです。
私が初めてPlaywrightを触った際に躓いた点についてまとめたものをご紹介します。私と同じミスで誰かの調べる時間が節約できるように、ここに残しておきます。
①テストコード書いたのにVSCodeに表示されない
これの原因はおおよそ2パターンあると思っています。
1つ目のパターンは”Node.jsのバージョンがおかしい”場合です。PlaywrightはNode.js16系以降での動作を要求するため、Node.jsのバージョンが低い、あるいは意図的に下げている場合はテストエクスプローラーにテストが何も表示されない、と言った症状が出ます。この場合はNode.jsのバージョンを上げてみて下さい。
2つ目のパターンはテストファイルの拡張子を間違えているパターンです。Playwrightがテストファイルだと認識してくれる拡張子は.tsではなく、.spec.tsです。この場合はテストエクスプローラーに拡張子を間違えたテストのみが表示されない、という症状が出るため、拡張子を直すことで表示させることができます。
②テストを実行したのにBrowser has been closedなどのエラーで止まる
テストを実行し、ページが表示されているにも関わらず”Browser has been closed(ブラウザが閉じられました)”が表示されることがあります。この場合の原因は様々考えられますが、私の場合は2通りありました。
1つはawaitを忘れた場合です。先ほどのコードで、page.gotoの前のawaitを消して実行してみると、おそらくBrowser has been closedエラーが出ると思います。
これは、awaitの付け忘れによって、ブラウザの遷移の結果を待たずに次の処理を行おうとしていることが原因です。そのため、awaitを付け忘れていないか、チェックしてみてください。
もう1つは背景などによってページが覆われていた場合です。皆さんは良くブラウザで何か要素を閉じようとしたときに、その要素の外側をクリックすることで閉じることがありませんか?これは、要素の外側にクリックを検知するための背景(のようなもの)を広げている場合があり、これが展開されている状態では、背景の下にある要素をPlaywrightは検知できません。そのため、人間が行っている操作と同じような操作(例えばどこか適当なところをクリックするなど)をPlaywright側で挟むことで解決できます。
③複数該当してしまう要素に対してテストを実行する
Playwrightは要素の指定をする際に、様々な方法を用いることができます。その中の1つに”~~というテキストを持っている”というgetByText()があります。ここで、複数候補があるような指定をすると、エラーになることがあります。極端な例ですが、getByText(“a”)で要素を取得し、それに対してtoBeVisible()をかけると、おそらくaを含む要素は複数ヒットするため、どの要素について表示を確かめているかわからず、エラーを吐かれる結果になります。実際に先ほどのコードに付け加えて試してみましょう。
import { expect, test } from '@playwright/test';
test('アイソルート: 製品・サービス紹介画面', async ({ page }) => {
await page.goto("https://www.isoroot.jp/business/");
await expect(page.locator('span').filter({ hasText: 'SmartGEMBA巡回点検ソリューション' }))
.toBeVisible();
await expect(page.getByText("a")).toBeVisible();
});
実行してみると、エラーが発生すると思います。
今回は”Error: strict mode violation: getByText(‘a’) resolved to 9 elements:”と表示されました。9個の要素でヒットしてるからどれか1つにしてくれ、といった感じですね。
これを絞る方法はいくつかありますが、今回は簡単なものを2つ紹介します。
1つは先ほどから使用しているPick locatorを使用する方法です。Pick locatorでは複数ヒットするような要素の指定は行わないため、そのままコピーしてテストに使用することができます。
もう1つは”複数ヒットした要素のうち何番目のものか指定する”方法です。こちらについては、先ほどのエラーにおいて、index.html上で番号が振られていたものを見て、何番目かを.nth(番号)指定することで要素を1つに絞る方法です。
※振られている番号は1からになっていますが、コード上で指定するときは0からなので、index.htmlでの数字から1引いたものを使用してください。
例えば、index.html上での3番目である”Dynamics CRM導入支援サービス”を指定する場合、先ほどのコードを以下のように修正します。
import { expect, test } from '@playwright/test';
test('アイソルート: 製品・サービス紹介画面', async ({ page }) => {
await page.goto("https://www.isoroot.jp/business/");
await expect(page.locator('span').filter({ hasText: 'SmartGEMBA巡回点検ソリューション' })).toBeVisible();
await expect(page.getByText("a").nth(2)).toBeVisible();
});
そのまま、何番目かを指定する感じですね。
これで実行すると、
無事にテストが完了しましたね。
このままでは本当にお目当てのものを確認できているかわからないため、少しコードを追加します。
import { expect, test } from '@playwright/test';
test('アイソルート: 製品・サービス紹介画面', async ({ page }) => {
await page.goto("https://www.isoroot.jp/business/");
await expect(page.locator('span').filter({ hasText: 'SmartGEMBA巡回点検ソリューション' }))
.toBeVisible();
await expect(page.getByText("a").nth(2)).toBeVisible();
await page.waitForTimeout(2000);
await page.getByText("a").nth(2).scrollIntoViewIfNeeded();
});
先ほどのコードに、2秒間待つ命令と、確認した要素までスクロールする命令を追加しました。スクロールはゆっくりとしたスクロールではなく、瞬間移動のため、あまり実感は湧かないですが、しっかりと”Dynamics CRM導入支援サービス”の位置に移動していることが確認できると思います。
このように、複数ヒットする方法で要素を指定するときは、後ろに.nth(番号)を付けることで指定することもできます。
④.toBeVisible()の扱いについて
先ほどから何度も登場している.toBeVisible()ですが、これには1つだけ注意すべき点があります。それは、.toBeVisible()は実際に画面に見えているかどうか、ではなく、そのページ内に可視な要素として存在しているかどうかをチェックしている点です。つまり、.toBeVisible()では、テスト実行時の画面内に表示されていなくても、画面外で表示されていればtrueで返ってくるということです。
そのため、”画面上に見えているかどうか”で判定したいときは.toBeInViewport()という別のアサーションが用意されているため、そちらを使うようにしましょう。余談ですが、Playwrightにはアサーションの結果を反転して使用する.notアサーションが用意されているため、.not.toBeInViewport()にすると画面上に表示されていないことを判定できます。
5. まとめ
今回はPlaywrightを知らない方に向けた簡単な紹介と、触り始めの初心者が躓いた落とし穴を書いてきました。
個人的な感想として、Playwrightは特殊な文法などがなく、かなり直感的なコードを生成できるため、新人エンジニアでも触りやすかったと思います。
PlaywrightはE2Eのテストをかなり楽にできるフレームワークであるため、毎回数十分以上テストにかけるようなことがあれば、自動化に踏み切るのもいいのではないでしょうか。