PlaywrightでVisual Regression Test実装する＋便利そうなオプションの紹介


## 初めに
この記事は[commmune Advent Calendar 2023](https://qiita.com/advent-calendar/2023/commmune)の12日目として投稿されました

## Playwright
PlaywrightはWebアプリのE2Eテストに用いられるNode.js上で動作するライブラリです。簡単にクロスブラウザ(Choromium, Firefox, Webkit)テストを実施できるので複数のブラウザをサポートするWebアプリ開発でのテストに最適です。

### Playwrightの初期設定

Playwrightの[公式サイト](https://playwright.dev/docs/intro)に沿ってPlaywright最新版のインストールを行います。

```
npm init playwright@latest
```

インストールの際に4つのオプションを選択できます。今回は以下のオプションでインストールします。

```
✔ Do you want to use TypeScript or JavaScript? · TypeScript
✔ Where to put your end-to-end tests? · tests
✔ Add a GitHub Actions workflow? (y/N) · false
✔ Install Playwright browsers (can be done manually via 'npx playwright install')? (Y/n) · true
```


下記のファイルを指定階層(playwright_vrt)にインストールできます、これでplaywrightのインストールは完了です。`playwright.config.ts`内でデフォルトでChormium,Firefox,Webkit環境でのテストが指定されていますのでテスト内容によってここを修正することで任意のブラウザを指定することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730894/86103ab0-c374-172f-f369-7532210bacdf.png)

### Playwrightの実行

下記コマンドでサンプルコードを実行できます。実行しているコードは`tests`フォルダにある'example.spec.ts'です。実行が完了すると`test-results`フォルダと`playwright-report`フォルダが同階層に生成され、'playwright-report'フォルダの中にテスト結果である`index.html`が生成されます。
```
npx playwright test
```
(補足)
`--ui`オプションをつけて実行するとテスト実行管理画面が開き、１段階づつテスト実行を追えるのでFlakyなテストコード修正やどこでテストが落ちているのかわからない時に便利です。
```
npx playwright test --ui
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730894/090ff1a3-2250-5976-27ae-ce84883cb7e4.png)

次に下記コマンドで実行結果を見ることができます。このレポートの中身としては上記の`index.html`に当たります。
```
npx playwright show-report
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730894/008a00f4-5538-6bb9-68fd-e97b31917329.png)

以上でPlaywrightの一連の流れは終わりです。次にPlaywrightを利用してVisual Regression Testを実装していきます。

## Visual Regression Test

Visual Regression Testは開発が既存のUIに影響を与えていないかを確認するためのテスト手法です。
以前のUIと現在のUIの差分を比較してくれるのでUI影響確認に便利なテストです。一般的に多く普及しているライブラリ、ツールとしては`reg-suit` `percy` `Chromatic`などがあります。今回は、Playwrightの既存機能とオプションのみを用いてVisual Regression Testを実装していきます。

## PlaywrightでVisual Regression Test

### テスト環境準備

Visual Regression Test用のテスト環境を準備します。既存のWebサイトでも構わないですが今回はUI差分確認ができているかの確認をしたいためローカル環境にReactをインストールし初期設定画面を利用して差分確認を実施します。

```
npx create-react-app my-app
cd my-app
npm start
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730894/b60918a9-32dc-fb55-1e3e-f99971dfbd4d.png)

### Playwright実装

PlaywrightでVisual Regression Testを実装するために標準装備されている`toHaveScreenshot()`を使用します。この機能はテスト中にスクリーンショットを撮影する機能ですが同時に、以前撮影したスクリーンショットとの差分を比較することができます。

初期インストールされた`tests`フォルダの中の`example.spec.ts`を下記のように修正します。

```javascript: /example.spec.ts
import { test, expect } from '@playwright/test';

test('React Visual Regression Test', async ({ page }) => {
  
  // go to localhost:3000
  await page.goto('http://localhost:3000');

  // Expects have screenshot
  await expect(page).toHaveScreenshot();
});

```

今時点では比較のためのスクリーンショットが撮影されていないのでこの状態で実行すると比較対象がないためエラーとなります。そのため、一度下記コマンドを実行して比較対象となるスクリーンショットを撮影します。
```
npx playwright test --update-snapshots
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730894/ed0ac6a4-1806-2c60-f51c-15b48d5772c1.png)

実行に成功すると比較となるスクリーンショットが取得できました。取得したスクリーンショットは新しく生成された`example.spec.ts-snapshots`フォルダにそれぞれのブラウザ毎格納されます。

最後に差分比較を実行します。
```
npx playwright test
```

現状は何もUIを変更していないので問題なく実行完了することができます(show-reportを見ても特にエラーは発生しない)。次に、UI変更が加えられた場合のケースについて紹介します。

### UIに差分がある場合

先ずはReact側に差分を作るために`../my-app/src/App.js`を修正しました。「Learn React」だった部分が「Playwright Regression Test」と表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730894/76caabac-cf71-a8b5-34ca-905ec9c28bc0.png)

この状態でPlaywrightを実行させるとUI差分が生じるのでエラーとなります。この時、`test-results`フォルダにエラーとなった画像が保存されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730894/a024b606-83f7-d7d4-44c1-9fb38aef1e32.png)

どの部分でUI差分が生じたのかshow-reportから確認することができます。下記の画面についてはshow-reportのトップ画面から各ブラウザの詳細エラー画面に遷移することで確認できます。

画像内では赤い部分がUI差分を表しています。また、「Actulal」を選択すると期待しているUIと現在のUIの差分をバーを動かすことでリアルタイムで目視することができます。どの部分がUI差分起きているかわからない、という時に一目瞭然なので便利です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730894/a9a3192b-3406-3c38-184a-da45bba6ef52.png)

![RVRT.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730894/0f117cd7-53c3-72dc-ac2e-c995b029b981.gif)

## toHaveScreenshot()のオプション

上記以外にもtoHaveScreenshot()にオプションを指定することで便利な使い方をすることができます。詳しくは[公式サイト](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1)に記載ありますが、今回は自分が実際に使ってみて便利そうだったオプションについて紹介していきます。

### フルスクリーン表示

Webアプリをフルスクリーンで表示してUI差分を取ることができます。スクロール処理が面倒な時などに便利です。boolean型でどちらかを指定することができます。
```javascript
  await expect(page).toHaveScreenshot({
    fullPage: true
  });
```

### マスク指定(無視する動的コンテンツを指定)

Webアプリによっては動的なコンテンツがある場合E2Eが落ちる原因となってしまいます。その場合`mask`オプションを使用することで動的なコンテンツのUI差分読み込みを回避することができます。

```javascript
import { test, expect } from '@playwright/test';

test('example test', async ({ page }) => {

  await page.goto('https://www.rakuten.co.jp/');

  await expect(page).toHaveScreenshot({
    mask: [
      page.locator('.r-slideshow-item-image'),
      page.locator('.video-section')
    ]
  })
});
```

今回は例として[楽天市場サイト](https://www.rakuten.co.jp/)を使用しています。楽天市場はユーザー毎によってログイン毎にTOP画面が変わるのでmask処理をしないとテストが落ちやすいです。

![VRT1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730894/63564046-af9b-c8b8-2669-6487fc92bb3f.gif)
![VRT2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730894/140017dd-eb91-ac99-661f-1018db2c0fc7.gif)

上の動画だとページに遷移する度にエラーとなりましたが、下の動画ではmask処理をしています。mask処理した範囲はピンクで表示されておりこの部分はUI差分に含まれません。これにより、テストをエラーなく完了することができました。

### 差分許容範囲指定

マスク指定するほどではないが許容したい差分範囲を操作したい時に使用します。範囲を広げることで自動テストが落ちにくくになりますがその反面厳密なUI確認には向いていないので多用はできない印象です。

```javascript
  await expect(page).toHaveScreenshot({
    maxDiffPixelRatio: 0.05
  });
```

### CSSアニメーション停止

アニメーションが流れるWebアプリの場合Visual Regression Testの妨げになることが多いです。そのため、そのようなアニメーションを停止するオプションを入れることで安定なテストを実施することができます。`animations`はboolean型ではなく`disabled`か`allow`を指定する必要があるので注意です。

```javascript
  await expect(page).toHaveScreenshot({
    animations: 'disabled'
  });
```


## その他便利なコマンド

今回はVisual Regression Testに焦点を当てましたが下記記事に便利なコマンドが纏められているので併用することでテスト内容を拡充することができます。
[これだけはおさえておきたいplaywrightコマンド集](https://qiita.com/oh_rusty_nail/items/d955e3273994214a0afa)