ビジュアルリグレッションテストについて
ビジュアルリグレッションテストとは
変更を加える前後でスクリーンショットを比較し、比較検証するテストのこと
目視で確認している「見た目」の変化を機械的に検出する
→ キャプチャ(画像)の差分を見ているため、1pxでも違う箇所があればエラーとして検出される
参考:スナップショットテストとは
似たようなテストとして、スナップショットテストがある、こちらは変更を加える前後でコンポーネントの出力(スナップショット)を取得し、比較検証するテストのこと
VRT(ビジュアルリグレッションテストは省略してVRTともいう)はユーザーが見る視覚的要素の差分を見るのに対して、こっちはマークアップそのもの(HTML)の差分を見る
スナップショットテストではCSS ModuleでのCSS変更した場合には差分として出してくれないかも?
ビジュアルリグレッションテストの必要性
ボタンなど共通のコンポーネントの見た目を変更した際に全呼び出し箇所で表示崩れしていないかを確認するのは面倒
意図していない場所で表示崩れしてしまっていないか影響の確認まで考えると大変
→ ビジュアルリグレッションテストがあることでページ全体を通して意図していない差分がないかを確認できる
またこういったテストがない場合のやりがちな開発アプローチは「すでにある定義には触れない」ということでリファクタリング等はせず追加改修で誤魔化すというアプローチになりがちになってしまう
→ 場当たり的な対応となり気がついたら闇深いコードになってしまう、こういったテストがあることでリファクタリングしようという考えを持ちやすくなるメリットもある
ビジュアルリグレッションテストのライブラリの種類
ライブラリ選択肢、組み合わせが多い問題
ビジュアルリグレッションテストのやり方を調べると多数のライブラリを目撃する
- Cypress
- Playwright
- reg-suit + Storycap
- 他 多数
今回ビジュアルリグレッションテストについてネット検索をしていると
- いろんなライブラリが出てきてよくわからない…
- どういったものを使えばいいの?
- なんでライブラリの組み合わせをしているの?
と疑問を持ったため、ライブラリの種類についてまとめてみる
ビジュアルリグレッションテストのライブラリの種類
① E2Eテストフレームワーク
Cypress、Playwright、Puppeteer などが挙げられる
E2Eテストフレームワークなのでブラウザの操作ができる、操作の一環でスクリーンショットができる
つまりE2Eテストの延長でVRTが実施できる
Playwrightは単独でスクリーンショットの比較検証もできて、Cypressは単独ではできないがcypress-image-snapshotを使ってVRTテストを行えるとか
② ビジュアルリグレッションテストに特化したライブラリ
jest-image-snapshot、reg-suit、reg-cli、BackstopJS などが挙げられる
名前の通りVRTを実施するために作成されたライブラリとなっている
reg-suitはスクリーンショットの比較はできるが、スクリーンショットを撮ること自体はできないので他のライブラリと組み合わせる必要あり
BackstopJSハスクリーンショット取得、比較両方できる
③ コンポーネントエクスプローラーツール
メモ:コンポーネントエクスプローラーツールとは、UIコンポーネントが独立した状態でどのように見えるのか比較検証するツール
StoryBookとかで、Storycapと組み合わせることでコンポーネント単位でスクリーンショットが撮れるとか
比較検証は別のツールを使う必要がありそう
どのライブラリを選択するか
以下観点がありそう
- E2Eテストを既に使っているか、使う予定があるか
- その場合はE2Eテストフレームワークを主軸に考えるのが良さそう
- E2Eテストフレームワークと、VRTライブラリで別のものを使うとそれぞれで学習コストがかかるため、同一のものを使うのが望ましいかも
- その場合はE2Eテストフレームワークを主軸に考えるのが良さそう
- StoryBookを既に使っているか、コンポーネント単位でVRTテストしたいか
- その場合はStoryBook + Storycap + α を組み合わせる選択肢が上がりそう
- 逆にStoryBookに依存したくない場合は選択肢からは除外するべき
- その場合はStoryBook + Storycap + α を組み合わせる選択肢が上がりそう
- 差分をどのように見たいか
- jest-image-snapshotでは画像の差分があった際にdiffの画像を見ることができる
- イメージとしては後述する ※① のような形になる
- reg-suit、Playwright、BackstopJSはレポート画面を出すことができて、差分を視覚的に確認することができる
- イメージとしては後述する ※② のような形になる
- jest-image-snapshotでは画像の差分があった際にdiffの画像を見ることができる
ビジュアルリグレッションテストを触ってみる
選択したライブラリ
今回は以下の点を考慮してPlaywrightを使ってみました
- E2Eテストの延長でVRTをやりたいため
- Playwright単体でスクリーンショット取得、比較ができる
- 差分が見やすい
- スナップショットはローカルに置いて確認ができる (他のライブラリでもできそうではあるが)
- テストを並列で実行できる (他のライブラリでもできそうではあるが)
テストページ作成
今回は React / Next.js のサンプルページを用意する
$ npx create-next-app@latest
npx: 1個のパッケージを1.484秒でインストールしました。
✔ What is your project named? … sample-vrt
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias? … No / Yes
$ cd sample-vrt/
確認環境について
react@18.2.0
next@13.4.13
$ node -v
v18.17.1
サンプルページ起動
$ npm run dev
http://localhost:3000
今回はこの画面を元に更新していく
Playwrightの準備
$ npm init playwright@latest
✔ 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
サンプルのテストファイルが既に作成されているためlocalhostを見るように修正
$ vim tests/example.spec.ts
import { test, expect } from '@playwright/test';
test('example test', async ({ page }) => {
await page.goto('http://localhost:3000/');
await expect(page).toHaveScreenshot({ fullPage: true });
});
ビジュアルリグレッションテスト実施
初回は比較する画像がないためエラーになるが、2回目は問題なく成功する
$ npx playwright test
Running 3 tests using 3 workers
3 passed (4.5s)
To open last HTML report run:
npx playwright show-report
次にちょろっとページを修正して再度テストを実施する
テストが失敗することを確認
$ npx playwright test
Running 3 tests using 3 workers
1) [webkit] › example.spec.ts:3:5 › example test ─────────────────────────────────────────────────
Error: Screenshot comparison failed:
...中略
3 failed
[chromium] › example.spec.ts:3:5 › example test ────────────────────────────────────────────────
[firefox] › example.spec.ts:3:5 › example test ─────────────────────────────────────────────────
[webkit] › example.spec.ts:3:5 › example test ──────────────────────────────────────────────────
Serving HTML report at http://localhost:9323. Press Ctrl+C to quit.
ページに差分があるため、テストが失敗し、レポートページが自動で立ち上がる
手動で見たい場合は以下のコマンドで確認することができる
$ npx playwright show-report
修正前の画像(Expected)、修正後の画像(Actual)、差分画像(Diff)が表示される
差分画像について、差分があるところについてのみハイライトされるので凄くわかりやすい ※①
ちなみに該当箇所に「 hoge」という文字を追加していました
差分について視覚的に見ることもできるのでわかりやすい
差分を受け入れる際には以下のコマンドにて、スクリーンショットを更新することができる
$ npx playwright test -update-snapshots
メモ
①
ブラウザでページを表示し始めた際にローディング画像を出しつつ、非同期で表示データを取得している場合の書き方は以下
// #list というIDを持つ要素が表示されるまで待つ
const order Sent = page.locator('#list')
await orderSent.waitFor()
何も対策しないと、スクリーンショットの結果としてはローディングが取得できるが上記の書き方で非同期でのデータ取得に対応できる
わざわざsleepしてスクリーンショットを撮るとかしなくて良いので便利
②
当然のことながら目に見えないところの差分については追えない
select boxのオプション追加などは差分に出なさそう
逆にスナップショットテストだと差分には出そう
③
クリックや更新処理などユーザーの操作に応じたテスト単位でVRT実施は大変そう
というよりそこまでいくともうE2Eテストの領域に見える
最初はページ毎に1つ初期表示のスナップショットを確認するだけでも大分ようさそうな肌感
④
ページ数が多く、キャプチャが多いとその分GitHubにアップロードすることになることに注意
ライブラリによってはAmazon S3に置いてあるスクリーンショットを比較するとかができるため必要に応じて検討した方が良さそう
ビジュアルリグレッションテスト導入例
以下のようにCICDに組み込むのが良さそう
- GitHubでプルリクエストを作成する
- プルリクエスト単位でアプリケーションの動作確認環境を作成する
- 作成した動作確認環境にてVRTテストを実施する
- 失敗時には結果のレポート画面等を見れるようにしておく
すごいざっくりだがこのような自動化をしておくと良さげ
詳細なやり方については使っている環境によって大分異なるため割愛
ビジュアルリグレッションテストの効果
LINEの例
制作現場におけるビジュアルリグレッションテストの導入 - 「LINEのお年玉」4年目の挑戦
導入した効果として、導入後にバグが30%少なくなったとか
どの粒度まで導入しての結果なのかがわからなかったが、とりあえず数値としての実績が出ている
ソフトバンクの例
毎日1時間でWebページ1,000以上のうち1pxの変化を逃さない、ソフトバンクのE2Eビジュアルリグレッションテスト取り組みについて
1000ページ以上のWebページに導入して、月100万以上分の動作確認ん工数が削減できたとか
大分盛っていそうな気がするが、しかしページ数が多いアプリケーションについてはVRTの効果は存分に発揮しそう
終わりに
- VRTのテストを書くこと自体は簡単そう
- 自動化の仕組みについて、認証があるページなどは対応が面倒そうだが、一度作ってしまえば保守も簡単そう
- 差分が出るたびにupdate-snapshotsを打たないといけないのは慣れていないと若干面倒に感じるかも
- 差分箇所について見やすい、良き
- 導入効果もありそう
つまりビジュアルリグレッションテストおすすめ!
コメントを書く
コメント一覧