ビジュアルリグレッションテストのすすめ

日々いろいろなWebサイトの制作や修正を対応していく中で、修正したページとは関係ない（と思っていた）ページで表示が崩れてしまったことってありませんか？

私はたびたび経験があります。

毎回目視で全ページをチェックすれば防げるのかもしれませんが、それは現実的ではありません。
自動で全ページをチェックしてくれて不具合があれば教えてくれる、そんな便利なツールがあればと何度も思いました。

どうやら現代の技術でそれは作れるみたいです。ビジュアルリグレッションテストというらしいです。

# ビジュアルリグレッションテストとは
ざっくりいうと「見た目の比較」をするテストのことです。
変更前のWebサイトのスクリーンショットを用意しておき、変更後のスクリーンショットを撮り比較することで、どこが変わったか差分を表示し確認することができます。
![名称未設定.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565564/87cd6483-6023-38a1-c733-8e6de7eae06c.gif)

# どうやって使うの
ビジュアルリグレッションテストを導入するための方法はいくつかあるのですが
今回は下記の２つを採用して実装しました。

- **Playwright**
Webテストと自動化のためのフレームワークです。
ローカルでChromium、Firefox、WebKitを使用し様々なブラウザ操作をすることができます。
今回はページの表示、スクリーンショットの撮影を担当しています。

https://github.com/microsoft/playwright

- **reg-suit**
ビジュアルリグレッションテストのためのツールです。
以前の画像と現在の画像を比較し、それらの違いをまとめたHTMLレポートを作成します。
今回はスクリーンショットの比較、AWS S3への結果レポートの保存を担当しています。

https://github.com/reg-viz/reg-suit

# 実装してみる
## playwrightの準備
```:zsh
% npm init playwright@latest

// ✔ TypeScriptとJavaScriptのどちらを使用しますか？
✔ Do you want to use TypeScript or JavaScript? · JavaScript
// ✔ エンドツーエンドテストをどこに置くか？
✔ Where to put your end-to-end tests? · tests
// ✔ GitHub Actionsのワークフローを追加しますか？
✔ Add a GitHub Actions workflow? (Y/n) · false
```
まずはplaywrightのインストールと初期設定をおこないます。
選択肢が出てくるので回答していきます。

## reg-suitの準備
```:zsh
% npm install -D reg-suit
```
合わせてreg-suitもインストールしておきます。

ここでインストールするプラグインが尋ねられるので
下記3つのプラグインをインストールしておきます。

- **reg-keygen-git-hash-plugin**
Gitのコミットハッシュを利用して、比較対象となるスナップショットのキーを検出するためのプラグインです。

- **reg-notify-github-plugin**
テスト結果をGitHubのリポジトリに通知するためのプラグインです。
このプラグインをインストールすると、PRへのコメントとコミットのステータスが設定されます。

- **reg-publish-s3-plugin**
スナップショット画像を取得し、AWS S3に公開するためのreg-suitプラグインです。

```:zsh
% npx reg-suit init

// ? reg-suitの作業ディレクトリ。
? Working directory of reg-suit. .reg
// ? .gitignoreファイルに".reg "エントリーを追加します。
? Append ".reg" entry to your .gitignore file. Yes
// ? ディレクトリには実際の画像が含まれています。
? Directory contains actual images. __screenshots__
// しきい値、範囲は0から1。 値が小さいほど、比較の感度が高くなる。
? Threshold, ranges from 0 to 1. Smaller value makes the comparison more sensitive. 0.01
[reg-suit] info Set up reg-publish-s3-plugin:
// ? 新しいS3バケットを作成する
? Create a new S3 bucket No
```
合わせてreg-suitの初期設定をおこないます。

```json: regconfig.json
  "plugins": {
    "reg-keygen-git-hash-plugin": true,
    "reg-publish-s3-plugin": {
      "bucketName": "S3バケットの名前"
    },
    "reg-notify-github-plugin": {
      "clientId": "GitHub AppのクライアントID"
    }
  }
```

GitHub AppのクライアントIDは下記を参考に取得してください。

https://github.com/reg-viz/reg-suit/tree/master/packages/reg-notify-github-plugin#github-app-and-client-id

## AWS S3の準備
reg-suitを使うためにはAmazon S3かGoogle Cloud Storageの用意が必要になります。
今回はAWS S3のバケットを使用しましたので軽く触れておきます。

:::note warn
今回の設定はセキュリティ的にデフォルトの設定よりもゆるくなっているため、しっかりと理解した上で設定を行ってください。
:::

### S3のバケット作成
普通に作成すれば基本的には問題ないのですが

![スクリーンショット 2022-04-10 18.43.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565564/ba7b88f7-2ff0-1f1f-d439-dc0a1f4d8774.png)

パブリックアクセスの設定は上２つのチェックを外さないと上手く動きませんでした。
- 「新しいアクセスコントロールリスト (ACL) を介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする」をONにする
「画像のアップロード」ができるようになる

- 「任意のアクセスコントロールリスト (ACL) を介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする」をONにする
「差分を確認できるHTMLファイルの閲覧」ができるようになる

![スクリーンショット 2022-04-10 18.45.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565564/e40413a9-97a7-0ace-76aa-0d36eff61a5e.png)

またオブジェクト所有者のACLも有効にしないとエラーで弾かれました。

### ユーザー作成
バケットにアクセス可能なユーザーもAWSのIAMで作成しておきます。
![スクリーンショット 2022-04-10 23.19.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565564/b391da71-37e8-d0b5-0c43-7a4f0731d122.png)

今回、ポリシーはAmazonS3FullAccessを選択しました。
きちんと設定したい場合は適宜調整してください。
ユーザーの作成時に取得した**ACCESS_KEY_ID**と**SECRET_ACCESS_KEY**はこのあと使用します。

### AWS CLIのインストール
設定にAWS CLIも必要なのでインストールします。
公式のインストーラーを使ってインストールしました。

https://aws.amazon.com/jp/cli/

```:zsh
% aws configure
AWS Access Key ID [None]: ACCESS_KEY_ID
AWS Secret Access Key [None]: SECRET_ACCESS_KEY
Default region name [None]: ap-northeast-1
Default output format [None]:
```
インストールが終わったので早速CLIで必要な情報を設定します。

## Playwrightでスクリーンショット撮る
Playwrightのテストコードを書きます。
```js:example.spec.js
const { test } = require('@playwright/test');

test('visual regression test', async ({ page }) => {
  await page.goto('https://playwright.dev/', { waitUntil: 'networkidle' });
  await page.screenshot({ path: '__screenshots__/screenshot.png', fullPage: true });
});
```
まずは試しにスクリーンショットを撮ってみます。

```json:package.json
  "scripts": {
    "test": "npx playwright test",
    "regression": "npx reg-suit run"
  },
```
npm-scriptsでタスクを書いて、楽に実行できるようにしておきます。

```:zsh
% npm run test
```
![e0e58c48ab9d-20220410.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565564/ca5f91c5-460e-d439-d256-55ad0c47f988.png)

無事スクリーンショットを撮れました。

## テスト用のページを用意してテストしてみる
今回のテスト用にローカルにこんなページを用意しました。
![スクリーンショット 2022-04-10 16.53.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565564/f7eca0f6-72fb-b36a-9404-0fe4ce8c35e9.png)

```diff_javascript:example.spec.js
- await page.goto('https://playwright.dev/', { waitUntil: 'networkidle' });
+ await page.goto('http://127.0.0.1:5500/index.html', { waitUntil: 'networkidle' });
```
スクリーンショットを撮るページをローカルに書き換えて、スクリーンショットの撮影とreg-suitのテストを実行します。
```:zsh
% npm run test
% npm run regression

> visual-regression-test@1.0.0 regression
> npx reg-suit run

[reg-suit] info version: 0.11.1
[reg-suit] info Detected the previous snapshot key: '■■■■■■■■■■■■■'
                                         ■ 0% | ETA: 0s | 0/1[reg-publish-s3-plugin] info Download 1 files from visual-regression-test-2022.
 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 100% | ETA: 0s | 1/1
[reg-suit] info Comparison Complete
[reg-suit] info    Changed items: 0
[reg-suit] info    New items: 0
[reg-suit] info    Deleted items: 0
[reg-suit] info    Passed items: 1
[reg-suit] info The current snapshot key: '■■■■■■■■■■■■■'
                                         ■ 0% | ETA: 0s | 0/7[reg-publish-s3-plugin] info Upload 7 files to visual-regression-test-2022.
 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 100% | ETA: 0s | 7/7
[reg-suit] info Published snapshot '■■■■■■■■■■■■■' successfully.
[reg-suit] info Report URL: https://visual-regression-test-2022.s3.amazonaws.com/■■■■■■■■■■■■■/index.html
[reg-notify-github-plugin] info Update status for ■■■■■■■■■■■■■ .
[reg-notify-github-plugin] info Comment to PR associated with main .
```
テストをパスしたので問題なしですね。
初回のテストの場合、このスクリーンショットがS3に保存され、次のテストのときに正としてチェックがおこなわれます。

### reg-suitのテスト
今度は試しにCSSを変更して意図しないスタイルにしてみます。
mainブランチからdevelopブランチを切って、そこに変更したCSSをコミットしてみます。
Githubでdevelopからmainへのプルリクエスト（PR）を出して、もう一度スクリーンショットの撮影とテストを実行します。
```:zsh
% npm run test
% npm run regression
```
![スクリーンショット 2022-04-10 16.24.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565564/cfb1bad4-ad21-7335-845b-7882563c535b.png)

テストが失敗しました。
差分があるということをPR上で通知してくれています。

this reportのリンクを踏んで詳細を確認してみます。

![スクリーンショット 2022-04-10 17.06.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565564/7c7f327b-b769-36d6-75f1-99ec7b60979f.png)

CHANGED ITEMSとして
差分が出ている箇所が赤く塗りつぶされています。

![スクリーンショット 2022-04-10 17.07.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565564/1a8e2612-dbe5-0f25-c75a-f9cc399365ae.png)
![スクリーンショット 2022-04-10 17.07.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565564/0a4104d0-af05-1376-1388-d543eda4290e.png)
5種類の方法で差分を比較することができるので
どこでどんな差分が出ているのかがわかりやすいですね。

cssを修正して再挑戦してみます。
![スクリーンショット 2022-04-10 17.18.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565564/12a23d46-36f2-6b19-d550-4ec9123aeada.png)

今度は差分が出ませんでした。
この状態になれば、意図しないスタイルの崩れは起こっていないのでマージしてOKの状態です。

ちなみに、差分が出た状態で現在の状態が正しければ、そのままマージすることで正しい画像が更新されて以後その画像が正となります。

# まとめ
**ビジュアルリグレッションテストはいいぞ**

やはり目視でチェックをしている以上、ミスや見落としは避けられないと思います。
ツールを使ったチェックをすれば、予期せぬ不具合の検知や大量のページのチェックも可能になります。
複数のCSSを読み込んでいたり、CSSの影響範囲が読めなくなっている混沌としたサイトの改修時など、古くから保守しているサイトほどこういったツールが役に立つと思います。

ぜひビジュアルリグレッションテストを導入してみて作業の効率化、品質の安定化に役立てていただければと思います。