Playwrightを使って実際のブラウザ動作からE2Eテストを作ろう！


この記事は「[【マイスター・ギルド】本物のAdvent Calendar 2022](https://adventar.org/calendars/7794)」2日目の記事です。

こんにちはmiruoonです。
今回はTypeScript（TS）などで手軽にWebアプリのE2EテストがかけるPlaywrightを紹介します。

# 前置き
- 作者はJestやTestingLibraryといった各コードテストツールを隅々まで使いこなしたことはないので、間違った記載があったらコメント欄で気軽にツッコんでください。
- 2022/11月末の情報となります。
- E2Eテスト初めて聞いたわ！よくわからんわ！っていう人は以下の記事が詳しいので、読んでおくと良いです。

https://qiita.com/mt0m/items/7e18d8802843d9f60d28

# 開発環境
- MacBook Pro (13-inch, M1, 2020)
- macOS Monterey 12.1
- Node.js v16.10.0
- yarn 1.22.19

# 今回作成したコードについて

コードはここに置いています。

https://github.com/miily8310s/playwright-ts

# Playwrightとは

https://playwright.dev/

Microsoftが開発したE2Eテスト用ライブラリです。E2EテストライブラリだとCypressあたりがメジャーだと思いますが、その中でもPlaywrightはクロスブラウザ/クロスプラットフォーム対応や多言語でのテストコード作成（CypressはJavaScript/TypeScriptのみ対応）が可能という特徴を持っています。

## 対応環境

- クロスブラウザ対応 -> Chromium（Google Chrome/Microsoft Edge）/WebKit（Safari）/ Firefox
- クロスプラットフォーム対応 -> Windows / macOS（Apple Slicon製でも可） / Linux
- 多言語でのテストコード作成 -> Node.js（TypeScript/JavaScript）/ Python / Java/.NET
- Docker
- GitHub ActionsといったCI

また現時点（2022/11月末）ではβ版ですが、Android用Google ChromeおよびiOS用Safariのエミュレータテスト機能も搭載しています。

今回はTypeScriptを使ったNode.js版Playwrightについて紹介します。

# 開発環境構築

## インストール

ではインストールしてみましょう。以下のページに従って進めます。

https://playwright.dev/docs/intro

適当な空フォルダでインストールコマンドを叩きます（今回はyarnでやりましたが、npm/pnpmでも可能です。）。

```bash
yarn create playwright
```

いくつか質問がありますが、これといったことがない限りEnterボタン連打で大丈夫です。
Playwright browsersのインストールが入るため、すこし時間がかかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/9c0942e8-2b5e-7c6b-7749-1b0869cc9ecd.png)

インストールが完了すると、こんな形で雛形が作成されます。`tests`フォルダと`tests-example`フォルダにデモ用のアプリも付属してきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/f364f816-ad8c-b8a4-d1a8-936dbe3176d6.png)

## テストの実行

以下のコマンドで`tests`フォルダにある`example.spec.ts`ファイルに記載されたテストが実行されます。

```bash
npx playwright test
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/18b8f15b-4bd8-35fe-9249-e701fb712a98.png)

また上記のコマンドを叩いたあと、`ctrl + c`で停止し、続けてこちらのコマンドを実行します。

```bash
npx playwright show-report
```

するとブラウザでテスト実施結果画面が見れます。macOSではChromium/WebKit/Firefoxの3ブラウザ環境で確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/3e258fb9-7919-28eb-312f-789bfbde5a29.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/2d1ff00a-337f-6724-80b8-274946ad8f73.png)

## vscode拡張機能について

拡張機能もしっかり完備されています。導入手順/使い方は下記ページに動画付きで詳しく書かれているので、本記事では詳しく触れません。vscodeを使っている方はぜひ試してみてください。

https://playwright.dev/docs/getting-started-vscode

# Test Generator

さてここからが本題です。Playwright最大の目玉であるTest Generator機能を使ってみます。
この機能ではなんと指定したURLのページで実際に動作すると、テストコードを自動で作成してくれる優れモノです。

https://playwright.dev/docs/codegen-intro

以下のコマンドで実行できます。

```
npx playwright codegen <確認したいURL>
```

では例として有名なクローンアプリである[conduit](https://demo.realworld.io/#/)にアクセスした際の例を紹介します（動画撮っていたのですが、コードがぼやけて見えなくなってしまったので今回はなしですみません。。。）。

```
npx playwright codegen https://demo.realworld.io/#/
```

出来たコードをコピーしたものがこちらになります。

```ts
import { test, expect } from "@playwright/test";

test("test", async ({ page }) => {
  await page.goto("https://demo.realworld.io/#/");
  await page
    .getByRole("link", {
      name: "Repellat nihil in magnam quasi.\nEt dicta at est laborum doloribus sit.\nQuia possimus necessitatibus magnam, est, nulla, reiciendis exercitationem neque et tenetur quia deserunt asperiores blanditiis doloribus ipsum beatae numquam.\nUllam rerum consequuntur occaecati error.\nPossimus consequatur consectetur doloribus voluptate nihil, tenetur sunt fugiat quae id, ducimus non. Eos necessitatibus officia quos. Et vitae aliquid autem occaecati repudiandae placeat repellat odit. Minus iure voluptates autem quam dicta. Iste consequatur aspernatur voluptas quibusdam sint beatae. Read more... necessitatibus sequi vitae doloribus",
    })
    .click();
  await page
    .getByRole("heading", {
      name: "Repellat nihil in magnam quasi.\nEt dicta at est laborum doloribus sit.\nQuia possimus necessitatibus magnam, est, nulla, reiciendis exercitationem neque et tenetur quia deserunt asperiores blanditiis doloribus ipsum beatae numquam.\nUllam rerum consequuntur occaecati error.\nPossimus consequatur consectetur doloribus voluptate nihil, tenetur sunt fugiat quae id, ducimus non.",
    })
    .click();
  await page
    .getByText(
      "Iusto laborum aperiam neque delectus consequuntur provident est maiores explicab"
    )
    .click();
  await page
    .getByRole("button", { name: " Follow Magda Parry" })
    .first()
    .click();
});
```

遷移した際の操作のテストコードが出来ていることがわかると思います。もちろんブラウザ操作になるので、あくまで雛形レベルになりますが、TSに疎いエンジニアでもテストが作れてしまうのは最大のメリットです。しかもお金もかかりません。

[Autify](https://autify.com/ja)みたいな本格的なローコードテストサービスに比べると流石に質が劣るものの、Playwrightから動作チェックしたあと、TSが書ける人に渡して綺麗なテストコードにしてもらう→仕様を満たせるかの確認ができるというシチュエーションが期待できます。

## ログインしないと入れないページで実施する場合

`cookies`や`localStorage`の情報をJSONファイルに登録しておいて確認する方法がサポートされています。

https://playwright.dev/docs/codegen#preserve-authenticated-state

## Test Generatorでもっと色んなテストがしたい

以下のページではスマホ・タブレット表示環境で作成する方法など様々なアプローチが紹介されているので、ぜひチェックしてみてください。

https://playwright.dev/docs/codegen

# テストコードの書き方
テストコードの内容がわかっている方がいいに越したことはないので、簡単ですがテストコードの書き方を説明します。[Jest](https://jestjs.io/)を触っている人なら文法が非常に似ているためスムーズに理解できると思います。

## 1. 公式のサンプルで流れを理解しよう

この公式ページでは

1. Playwright公式ページにアクセス
2. ヘッダーの「Get started」ボタンを押下
3. introページに遷移

というストーリーのテストコードを例に、どんなチェックを行っているかの説明がされています。コードも含めて平易な英語で書かれているのでこれである程度やることは掴めたかなと思います。

https://playwright.dev/docs/writing-tests

## 2. サンプルテストコードを書いてみる

今回の記事ではまた[conduit](https://demo.realworld.io/#/)を使って、実際にテストを書いてみましょう。

テストコードファイルに関しては以下の2点に注意しながら作成しましょう。
- Playwrightのインストール時に特に指定してなければ、ディレクトリ直下の`tests`フォルダに設置します
- ファイル名は`aaaa.spec.ts`になります

```tests/conduit.spec.ts
import { test, expect } from "@playwright/test";

test("conductにアクセス", async ({ page }) => {
  await page.goto("https://demo.realworld.io/#/");
  // ページタイトルを取得
  await expect(page).toHaveTitle("Home — Conduit");
});
```

まずは、`toHaveTitle`関数を使い、ページタイトル（ブラウザだとタブに出ている文字列）を確認するテストを書いてみました。そしてターミナル等で次のコマンドを叩きます。

```bash
npx playwright test
```

成功したのでコマンドラインにテストがpassされたことの確認が表示されます。Cypressのようにブラウザが表立って立ち上がったりはしないのでサクサクです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/8716158f-e66f-9ca0-a232-6139b1a42404.png)

コード中に登場した変数`page`はテスト実行中に開かれるページそのものと思ってもらってかまいません[^1]
[^1]: 詳しく知りたい方は[こちら](https://playwright.dev/docs/api/class-page)を参照。

ページの一部分を表す変数もあるのですが、こちらは後述します。

### テストが失敗したとき

もちろんテストコードなので失敗することもあります。失敗するとレポート画面がブラウザ上に立ち上がり、どこでコケたか、実際の値はこうであるを伝えてくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/646fe1fa-8069-c143-08f3-bd8e7a8c000f.png)

## 3. テストをどんどん書き進めていこう

テストコードにボタンのクリックイベントを追加してみました。今回は簡単にページ遷移することの確認をテストしています。

```diff_typescript
import { test, expect } from "@playwright/test";

test("conductにアクセス", async ({ page }) => {
  await page.goto("https://demo.realworld.io/#/");
  // ページタイトルを取得
  await expect(page).toHaveTitle("Home — Conduit");

+ // テキストが書かれた特定の要素を取得
+ const placeText = page.getByText("A place to share your knowledge.");
+ // 要素が存在していることを確認
+ expect(placeText).toBeTruthy();

+ // Sign inボタン要素を取得
+ const signInLink = page.getByText("Sign in");
+ // Sign inボタンをクリック
+ await signInLink.click();
+ // 遷移先ページの確認
+ await expect(page).toHaveURL("https://demo.realworld.io/#/login");
+ await expect(page).toHaveTitle("Sign in — Conduit");
});
```

Playwrightでは、ページの一部分（要素）を表す変数のことを`Locator`と呼びます。
`Locator`を定義しておくことによって、短い構文で書くことができるなどのメリットが受けられます。

https://playwright.dev/docs/writing-tests#locators

なお、`Locator`で使えるクリックや入力などのイベントの一覧はこちらから確認できます。

https://playwright.dev/docs/api/class-locator

# テストの実行コマンドについて

テストコードが増えていくと、「このテストだけ実行したい！」「このファイルだけ実行したい！」な場面が出てくるかと思います。
Playwrightではそのための実行コマンドがたくさん用意されています。

なお、前述したvscode拡張機能を使うとGUIベースで実行できるようになるため、使いやすい方で試してみてください。

https://playwright.dev/docs/running-tests

# もっとE2Eテストを知りたい！

Playwrightのリポジトリでは、公式のサンプルコードがいくつか公開されています。
初心者は特に以下のコードをオススメします。todoリストを題材にしたテストコードとなります。

https://github.com/microsoft/playwright/blob/main/examples/todomvc/tests/integration.spec.ts

# 使ってみた感想

筆者は少しCypressを使った経験がありますが、Cypressと比べると
- 導入コストの低さ。
- Test Generator機能のおかげで、フロントエンドエンジニアでなくても手順さえ教えれば自動である程度のテストコードが作れる。
- テストコードの書き方がJestライクなので馴染みやすい。
- 各機能でやれることが明確かつ理解しやすい。ドキュメントのスクリーンショットや動画も豊富。
- バージョンアップが頻繁に行われており、今後も機能追加が期待できる。

などの好印象を受けました。ベータ版時代を含めても2020年登場の後発ライブラリでありながら、CypressよりもGitHubのスター数を上回っている理由も納得します。

デメリットとしては
- 実験的機能も少なくない。やりたい機能も実験段階である場面に遭遇しがち。
- 圧倒的に情報が少ない。本番環境事例もまだまだ少ない。

くらいでしょうか。

ドキュメントを見る限り、本当にテストできることが多いので今後個人開発でも業務でも取り入れていきたいです。

# おまけ

## Playwrightで出来るE2Eテスト以外のテストの紹介
PlaywrightではE2Eに留まらない様々なテストが実行できます。E2Eテストに組み込むことも簡単にできます。

## APIテスト

APIテストはcurlコマンドやPostman/Swaggerで叩いて確認することが多いですが、簡単にレスポンス値の確認が出来ます。

https://playwright.dev/docs/test-api-testing

## Visual Regression Testing

Visual Regression Testing（VRT）と呼ばれるテスト手法があります。
テスト実行時にUIのスクリーンショットを撮り、次のテスト実行時に以前のスクリーンショットとの差分をチェックできるため、CSSも含めたUIチェックが自動でできるメリットがあります。

ただし筆者自身の所感としては、以下の記事で触れられているように、[Storybook](https://storybook.js.org/)の導入が前提となっている上に他サービスとの共用が絡んでくるケースばかりで、Storybookの導入が難しい環境下ではまず導入できない印象を受けていました。[^2]
[^2]: Reactといったフレームワークがそもそも導入されていない。コンポーネント化前提でコードが組まれていないといった状況が該当します。

- [今さら聞けないビジュアルリグレッションテストをChromaticで始める](https://buildersbox.corp-sansan.com/entry/2022/08/01/110000)
- [ABEMAでスナップショットテストをやめてVisual Regression Testingに移行する話](https://developers.cyberagent.co.jp/blog/archives/29784/)

PlaywrightではStorybookなしでも、スクリーンショットさえあればVRTが実行できます[^3]。
[^3]: snapshotと聞いてJestのsnapshot機能を思い出す人もいると思いますが、JestはHTMLコードレベルまでしか見てくれません。

https://playwright.dev/docs/test-snapshots

必要なスクリーンショットを取得するための機能も充実しています。ただしローカルに置かれた画像ファイルのみで、外部画像URL（AWS S3に設置した画像ファイルなど）とのチェック機能はまだないため、ここは今後の機能追加に期待です。

https://playwright.dev/docs/screenshots
https://playwright.dev/docs/cli#take-screenshot

## コンポーネントのテストコード

:::note warn
こちらは実験的機能となります。
今後破壊的な変更が行われる可能性があるので、最新情報は公式ドキュメントを参照ください。
:::

コンポーネントのテストコードも作成出来ます。現在対応しているフレームワークはReact/Vue.js/Svelte/Solid.jsの4つです。もちろんhooks系メソッドのテストにも対応済みです。

https://playwright.dev/docs/test-components

コンポーネントのテストライブラリではメジャーな[Testing Library](https://testing-library.com/)ユーザーのために、移行ガイドもすでに掲載されています。

https://playwright.dev/docs/testing-library

## 参考資料集

- [Playwrightを用いたテスト自動化](https://www.cresco.co.jp/blog/entry/20355/)
- [Playwright でコンポーネントテスト](https://zenn.dev/azukiazusa/articles/playwright-component-testing)
- [Playwright & Vite ではじめる脱レガシー向け軽量 Visual Regression Test](https://blog.cybozu.io/entry/2022/03/18/100000)
- [PlaywrightによるSvelteコンポーネントテスト](https://speakerdeck.com/kubotak/playwrightniyorusveltekonhonentotesuto
)-> 数少ない本番環境での導入事例が紹介されています。
- [Web開発を補助する目的でPlaywrightを使っている話](https://speakerdeck.com/aokiken/webkai-fa-wobu-zhu-surumu-de-deplaywrightwoshi-tuteiruhua) -> 少し変わった方法で使う話です。

記事は以上となります。