手軽に Visual Regression Testing を始めよう!
きょんしー🐧 です。
最近はUIを作るよりテスト環境整備したりFeature Flag導入したりVite試したりRenovate運用考えたり、継続して開発していくためのことが多めになってます。
この記事ではVisual Regression Testing(以降、VRTと記述する)を手軽に始めてもらえるよう、HiTTOでの導入例を紹介します。
- VRTの導入を試みたが失敗した
- VRT導入してみたいけどよく分からない
といった方に向けた記事になります。
※ Storybookを導入している前提になってます🙇♂️
そもそもVRTとは?
そもそものVRTはどのようなテストかについてですが、ブラウザにレンダリングした際のスクリーンショットをピクセル単位で差分を検出するテストです。
正解画像(Expected Image)と実際の画像(Actual Image)を比較し、 差分が閾値以下ならSuccess、しきい値を超えたらFailedになります。
UIの変更をした箇所とは異なる箇所に影響が出ないかをテストすることができます。
正解画像(Expected Image)と実際の画像(Actual Image)を1px単位で比較してくれるので、差分があれば以下のように表示してくれます。
VRTの導入は敷居が高い?
僕自身も前職でVRTを導入しようとしましたが、以下のような壁があり断念しました。(HiTTOでやっと雪辱を果たしました🎉)
- CI上でフォントの読み込みが解決できなくて日本語が豆腐になる
CircleCIであればフォントを追加してあげればOKです👍HiTTOでは日本語フォントにNoto Sans、英数字フォントにLatoを用いてるので fonts-lato
, fonts-noto
, fonts-noto-cjk
を追加しています。
- run: name: apt-get install command: | sudo apt-get update sudo apt-get install libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb sudo apt-get install fonts-lato fonts-noto fonts-noto-cjk
- サーバーの立ち上げを待ってスクショを取得する
この後も登場しますが、start-server-and-test
を使用すればサーバーが立ち上がるまで次の処理を待つことができます。
これ以外にも理由はあるかもしれませんが、Jestを導入することに比べると敷居が高いように感じています。
また、VRTは(ヘッドレス)ブラウザを立ち上げる必要があるため導入できたとしてもCIの時間がかかる懸念もあるでしょう。最初から運用に乗せようとすると苦労すると思うので、小さく導入して効果を実感できれば敷居も下がるのではないかと思います。
StorybookにVRTを導入する
HiTTOではStorybookを使っており、デザインの認識合わせに用いています。Atomic Designを採用しているのですが、Templates以下の全てのコンポーネントを確認することができます。
参考: フロントエンド × デザイン 〜連携強化のためにしていること〜 - HiTTO プロダクトチームブログ
Templates内にある各storyに対してVRTを行なっています。
Templatesに限定している理由は、CIでの実行時間を短く抑えたいこととページAのレイアウトを変更した際にページBにまで変更が及んでないかを確認するためです。
Storybookに対してVRTの導入する方法としてStorycapを用いる方法もあったのですが、全storyのスクリーンショットを取得する必要ないかなと判断しCypressでスクショを取得するようにしました。Storycapは各Storiesをクロールしてくれるため、手軽にスナップショットを取得できるそうなので、試してみたいです👀
- Cypress: Headlessブラウザを起動してStorybookのスナップショットを取得する
- reg-suit: キャプチャした画像と正解画像の比較、GithubやSlackへの通知、GCSとの連携
Cypress
Cypressのセットアップ から説明します。
$ yarn add -D cypress
$ yarn run cypress open
起動できること確認したら閉じて、cypress/integration/examples
ディレクトリ以下は不要なので削除します。
次に、Storybookサーバが起動するのを待ってスナップショットを取得する必要があるので、start-server-and-test
をインストールします。
$ yarn add -D start-server-and-test
スナップショット取得の処理を記述します。
CI上で動かすことを考えたときの適切なcy.wait(3000)
の値を探る必要はありそうです。
context('Storybook', () => { it('logged in', () => { cy.visit('http://localhost:6006/?path=/story/example-page--logged-in'); cy.wait(3000); cy.get('#storybook-preview-wrapper').screenshot('login'); }); });
以下のコマンドをnpm-scriptsに記述した上で実行すると、
cypress/screenshots
ディレクトリ以下にスナップショットが出力されます。
start-server-and-test 'yarn storybook' http-get://localhost:6006 'yarn cypress:run'
reg-suit
次に、reg-suitについて説明します。
$ yarn add -D reg-suit
$ yarn run reg-suit init
最初はローカル環境でVRTを実行するために、plugins周りは省いてます。
{ "core": { "workingDir": ".reg", "actualDir": "cypress/screenshots", "thresholdRate": 0, "ximgdiff": { "invocationType": "client" } } }
.reg/expected
ディレクトリにcypress/screenshots
ディレクトリをコピーする- コンポーネントに変更加える
- Cypressを実行する
reg-suit run
npx http-server .reg
でローカルサーバ立ち上げる
pluginsの設定
reg-publish-s3-plugin
(reg-suitの結果の置き場所。gcsのpluginもあります), reg-notify-github-plugin
(github連携), reg-keygen-git-hash-plugin
を追加しました。
{ "core": { // 省略 }, "plugins": { "reg-keygen-git-hash-plugin": true, "reg-notify-github-plugin": { "prComment": true, "prCommentBehavior": "default", "setCommitStatus": false, "clientId": "need to setup" }, "reg-publish-s3-plugin": { "bucketName": "need to setup" } } }
Github連携をしているとpull-reqに自動で結果をコメントしてくれるので、予期せぬレイアウトの崩れをVRTによって見つけることができるのでとても助かっています!
※ ここではGithub ActionsやCircleCIの設定に関しては触れませんでしたが、reg-suitに注意点が示されています。
最後に
HiTTOでは複業で関わってくださる方も在籍し、複業から始めていただいた上で日々の開発や1on1を通してお互いにマッチするかを確認しています。
良いUIの良いサービスとは何かを考えて継続的に届けたい!フロントエンド開発でいろんなことにチャレンジしたい!方を募集しています。HiTTO気になってるけどカルチャーにマッチするか不安だなぁという方はカジュアル面談も行っているので是非お声がけください!