目次
目次
- はじめに
- 前提
- Lost Pixelとは
- セットアップ
- プロジェクトに適用
- 運用シナリオ
- ローカルで確認
- 運用の準備
- 運用する
- まとめ
はじめに
2月に開催された#vrt4選という勉強会に参加した際、その中で紹介されていたLost Pixelというツールに興味を持ちました。
👇該当のスライド
普段は専らChromaticユーザなのですが、個人開発の際、無料枠の上限にヒットして痛い目にあった過去があるので、今回個人ブログではLost PixelでVRTを行うことにしてみました💸
#vrt4選では詳細な実装やVRTの一連の流れまで述べられていなかったかつ、Lost Pixelはまだあまり普及しておらず、発表者の方のスライド以外で使用例があまり見つからなかったため、今回はLost Pixelを用いた具体的なVRTの運用方法をまとめてみました。
前提
前提として、Next.js製のブログアプリを含むモノリポ構成でできている、このブログアプリの/apps/blog
マイクロサービスにVRTを施していきます。
ブログアプリの全体像は以下の通りです。
Next.jsでSSGとmarkdownを使用したブログアプリを作成する
saku's Techblog
https://blog.sakupi01.com/dev/articles/blog-tech-stack
Lost Pixelとは
Lost Pixelとは、VRT(Visual Regression Test, ビジュアル回帰テスト)を行うためのツールです。
Lost Pixel - holistic Visual Regression Testing cloud
Easy to integrate and reliable visual regression testing cloud. Sleep better at night while shipping features.
https://www.lost-pixel.com/
簡単に、VRTとは、コードベースの変更の前後でビジュアル的な(ここではWeb UIに対して)意図せぬ変化が生じていないかを検知するテストです。
VRTはUnitテストやIntegrationテストを代替するものではなく、これらのテストに加えて、人間が目視で認識しにくい部分のデグレでも、機械的に自動で見た目の正当性を担保するためのテストです。
VRTに関するより詳細な説明は以下を参照ください。
Lost Pixel Blog - Visual regression testing 101
Your entry point into the Visual Regression Testing world
https://www.lost-pixel.com/blog/visual-regression-testing-101
VRTを実現するためのツールは、Chromatic, storycapでのスナップショット+reg-suitでの差分比較などが挙げられますが、Lost PixelのOSSモードを使用すると、私がこれまで使用した範囲では以下のような利点がありました。
⭐️メリット
- OSSモードだと、Githubをフル活用することで、無料でVRTできる基盤が作れる
- StorybookやLadle, Histoire, ページ単位のスクリーンショット、CypressやPlaywrightを用いたスクリーンショットなど様々な撮影方法が可能
- VRTでの差分チェックをGIthubでのPRレビューに組み込める
- マスキング機能があり、コントロールが難しいランダムな要素を差分チェックから除外でき、本質的な部分の検証が容易
- ズレの閾値やスクリーンショットを撮るまでの待機時間、networkRequestやページロードのタイムアウト時間を細かく設定できる
- configファイルがTypeScriptで書ける
重複した説明が発生するため、ここでは簡単な説明に止めて詳細はスライドやZennの記事に譲りたいと思います。
セットアップ
ページ単位のスクリーンショットのため、以下のドキュメントのPage shots部分を参照します。
Modes | Lost Pixel
https://docs.lost-pixel.com/user-docs/setup/project-configuration/modes#page-shots
ベースは上記の通りですが、今回はモノリポかつCIの使用ということを加味して、以下のように変更を加えています。
プロジェクトに適用
運用シナリオ
早速、プロジェクトにLost Pixelを適用していく手順を見ていきます👀
まず、今回の運用シナリオは以下とすることにします。
- モノリポの
apps/blog
で実装されているブログアプリのマイクロサービスに対して、ページ単位のスクリーンショットを撮ることでUI差分比較
- デフォルトブランチを
main
, Lost Pixelを取り入れるためのブランチをfeat/lost-pixel
とする
- featureブランチ
feat/lost-pixel
のPRチェック時にGithub ActionsでLost Pixel OSSモードを用いたVRTを行う
- 差分が検出された場合は
/update-vrt
とPRにコメントを入れることで、ベースライン画像の更新PRlost-pixel-update/[base-pr-name]
を元ブランチfeat/lost-pixel
から新たに作成する
lost-pixel-update/[base-pr-name]
のベースライン画像の差分をImage Diffを用いて確認・レビューし、マージする
- 元ブランチ
feat/lost-pixel
上でVRTが再度走り、チェックがpassする
おおまかな流れを掴んだところで、実際に手順を確認していきましょう🏋🏻
ローカルで確認
0. ローカルで差分確認する
package.json
に以下のコマンドを追加します。
セットアップで設定したlostpixel.config.ts
の内容をよく見ると、環境変数の値によって設定値を変えている部分があるので、そこを加味したスクリプトにします。
上記のようにLOCAL=true
としているのは、npm scriptsを使用して実行するのはローカルだけで、CIではlost-pixelのアクションを使用するので、このscriptsのLOCAL環境変数はtrue
に設定しておいて問題ないです。
以下のコマンドで、手元の環境で差分を確認してみると、わたしのプロジェクトでは以下のようにスナップショットが出力されます。
lost-pixel初回実行の出力
1. baselineをupdateする
ところが、初めて実行すると、以下のように、「baselineのスクショがないから比較できないよ〜」の例外がスローされます。
なので、ベースラインとなる画像をアップデートして、比較基準を生成してあげます。
すると、以下のようにbaseline-imagesにベースライン画像が格納されていることが確認できます。
ベースライン画像が生成される
しかし、baseline-imagesとcurrent-imagesの比較がベースライン画像のアップデートよりも先に行われている可能性があるからか、またもや例外がスローされます。
2. もう一度差分確認をする
とはいえ、base-imagesの更新はできているようなので、もう一度差分の確認をします。
すると、今回は例外はスローされずにプロセスが完了しました🎉
この流れをCI上でもおこない、PRマージの際に自動チェックしていきましょう🏌🏻♀️
運用の準備
3. Workflowを作成する
Github Actionsを用いてCIとして動かすためのWorkflowファイルを作成していきます。
運用シナリオで述べた以下の流れを実現するために、次からの項目でvis-reg-test.yml
とupdate-lostpixel.yml
を作成します。
- featureブランチ
feat/lost-pixel
のPRチェック時にGithub ActionsでLost Pixel OSSモードを用いたVRTを行う
- 差分が検出された場合は
/update-vrt
とPRにコメントを入れることで、ベースライン画像の更新PRlost-pixel-update/> [base-pr-name]
を元ブランチfeat/lost-pixel
から新たに作成する
lost-pixel-update/[base-pr-name]
のベースライン画像の差分をImage Diffを用いて確認・レビューし、マージする
- 元ブランチ
feat/lost-pixel
上でVRTが再度走り、チェックがpassする
(P.S. このCI workflowを作成するのに多くの時間を消費しました。私はCIにとても弱いです。(CIスパスパ作れる人々かっこいい。。。))
3.1 差分確認のためのWorkflow(vis-reg-test.yml)
vis-reg-test.yml
の役割はlost-pixel/lost-pixelというアクションを利用した単純な差分チェックです。
ワークフローの各ステップの内容は# 🟢...
で示しています。
3.2 baseline更新のためのWorkflow(update-vrt.yml)
4. update-vrt.ymlをmainブランチに取り込む
実際にfeat/lost-pixelブランチのPRを作成してvis-reg-test.yml
のワークフローを回す前に、運用の下準備としてupdate-vrt.yml
をmainブランチに取り込んでおきましょう。
feat/lost-pixelブランチにそのままupdate-vrt.yml
をコミットしたい気持ちですが、このままではPRに/update-vrt
をコメントしてもワークフローはトリガーされません。
update-vrt.yml
のトリガーは「PRに/update-vrt
をコメントする」ことで、pull requestのコメントが作成、編集されたときにワークフローを実行するために、issue_comment
を利用しています。(update-vrt.yml
の内容を参照)
ここで気をつけたいのが、トリガーするイベントがissue_comment
のワークフローファイルがデフォルトブランチに存在しないと、PRにコメントしてもワークフローはトリガーされないということです。
ワークフローをトリガーするイベント - GitHub Docs
GitHub で特定のアクティビティが実行された時、スケジュールした時間、または GitHub 外でイベントが発生した時にワークフローを実行できるよう設定できます。
https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows#issue_comment
注: このイベントは、ワークフローファイルがデフォルト ブランチにある場合にのみワークフローの実行をトリガーします。
したがって、前もってupdate-vrt.yml
をmainブランチにコミットしておきます。
運用する
6. vis-reg-test.ymlを回す
feat/lost-pixel
のPRを作成してvis-reg-test.yml
で定義されているワークフローを回します。
以下の6.**のステップで、ワークフローの実行結果によってとる行動を示します。
6.1 Failのとき
/update-vrt
とPRにコメントします。すると、先ほど定義したupdate-vrt.yml
のワークフローがトリガーされます。
これにより、baselineのupdateをするためのブランチlost-pixel-update/[base-pr-name]がコメントを入れたPRから生える形で作成されます。
次に、タイトルが「Lost Pixel Update - [base-branch-name]」PRも作成されます。
早速、作成されたPRを見ていきましょう👀
PRのChanges部分を確認することで、Github上で視覚的に見た目の変化を捉えることができます。
👇微々たる変化。この場合、キャプチャタイミングや実行環境の差異が原因であると思われる。
フォントによるズレ(環境の差異として今回は許容)
→ステップ6.1.1へ
👇見た目の大きな変化。この場合、コードベースに何らかの問題があると思われる。
zennの記事を表示する変更を加えた際、定義した環境変数が正しく読み込まれていなかったことによる不整合
→ステップ6.1.2へ
6.1.1 許容可能な見た目の変化のとき
PRの差分を確認した結果、許容可能な見た目の変化の時は、コメント元のブランチ(feat/lost-pixel)に6.1で生成されたPRをマージしたいです。
そうすることで、コメント元のブランチのbaseline画像がアップデートされ、vis-reg-test.yml
のワークフローのテストをpassすることができるはずです。
許容可能な見た目の変化だと確認できたら、6.1のPRをマージしましょう!
すると、コメント元のブランチ(feat/lost-pixel)でもう一度vis-reg-test.yml
のワークフローが周り、今度はupdateされたbaselineとの比較が行われるため、テストをpassすることができます
→ステップ6.2へ
6.1.2 許容不可能な見た目の変化のとき
コメント元のブランチ(feat/lost-pixel)に戻って、見た目を揃えるための修正コミットを加え、再度pushします。
→ステップ6へ
6.2 Successのとき
おめでとうございます!これで見た目が確認された変更をマージできます💯
まとめ
Lost PixelとGithub Actionsを使用してVRTを運用するプロセスを具体例ベースでまとめました。
日本語文献どころか、英語文献ですら具体的なユースケースが出てきにくいLost Pixelの使用で詰まってしまうところも多かったので、備忘録としての役目も兼ねて書きました。
今回はページ単位でのキャプチャの差分比較でしたが、Storybookを用いたコンポーネント単位のユースケースも考えられ、コストフリーでVRTをする場合、Lost Pixelは有力な候補になりそうです。
CIのworkflow部分上手く書けている気がしないので、私の周りのCIつよつよエンジニアの方からのアドバイスお待ちしています笑📨