ビジュアルリグレッションテストを導入して見た目の変化に気づける様にする

こんにちは、 @lulu_ulul です。普段は鳥取からフルリモートで勤務しています。

Misoca では年に数回全員でオフィスに集まる日がありまして、先日久々に鳥取から名古屋オフィスに行き楽しんで来ました。

その時にメンバーに「あれ、髪染めました?」と聞いたのですが、「いや、染めたの結構前ですよ…」と返されてしまいました。。。

Zoom 等のカメラ越しだと色味の変化に気づきにくいのもあるのですが、私の様な目diff 性能が低い人間には細かな差を認識するのは難しいですね。

違いの分かる男になりたいです。


目視でデザインの変化を確認・検知するのがつらい…

日々のライブラリのアップデートや新機能をリリースする際に意図しない箇所のデザインに影響が出ていないか心配になりますよね。 また、CSS の整理やコンポーネントリファクタリング等を行う際にも、影響が出る懸念やその確認作業の大変さから中々踏み出せない事もあると思います。

自動テストにより機能面での振る舞いやコンポーネントの有無の検証はしていますが、関心の無い領域も含め視覚的な面での振る舞いまで記述し検証・保守する事は難しいです。

また テスト環境と本番環境とでどうしても差異が存在するため振る舞いが変わってくる可能性があります。 かといって目diff による検出を続けるのは時間的にも精度的にも厳しいです。

実際にデザイン崩れが起きた事例

冬頃に CSS の build を高速化するために libsass の導入を行ったのですが、その際に一部のモーダルウィンドウの表示位置がおかしくなってしまい、一部のユーザの方にご迷惑をおかけすることになってしまいました。

勿論その時も目視による確認作業は行っていたのですが、ファーストビューに存在しないモーダルなのもあって見落としてしまったのが原因でした。


前述の問題点の解消と上記の様な不具合の再発を防止するために、 Misoca でも開発生産性向上の一環としてビジュアルリグレッションテストの導入を始めました!

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

視覚的な回帰テストの名の通り、スクリーンショット等を撮影しておき前後で差分が出ていないか検証するテストです。

テスティングフレームワークとして BackstopJS や LOKI 等いくつかあるのですが、 今回は以下の理由から reg-suit を選びました。

f:id:lulu-ulul:20180426140702p:plain

reg-suit

  • プラグインにより以下の機能が簡単に使える
    • コミットログベースでの比較対象の自動選定 も 文字列ベースでの比較対象の指定 の両方に対応
    • S3への画像・レポートのアップロード
    • GitHub の PR や Slack への自動コメント・通知が行える
  • 画像群を比較しレポート作成するまでが責務のため 画像群生成の部分の自由度が高い
  • レポート画面が見やすく画像ファイル名ベースのインクリメンタルサーチが行える
  • x-img-diff-js を利用した際の差分検出・表示が良さそう

reg-suit

Jenkins にJob を設定し、以下の2つを行える様にしました。

  • 本番環境上で定期的に前回成功ビルドとの差分を検出するテスト
    • ユーザが目にする環境に差分が出ないかの検出が目的
    • Jenkins の build 番号を使った文字列で reg-simple-keygen-plugin によるテストを実行
  • ステージング環境上で各ブランチ毎に master ブランチの最新実行結果との差分を検出するテスト
    • シナリオの開発・変更時用
    • ステージング環境を対象にしているので、リリース前に確認したい影響範囲の大きそうな場合にも使用可能
    • git の コミットログから比較対象を自動選定する reg-keygen-git-hash-plugin によりテストを実行

f:id:lulu-ulul:20180426112044p:plain

また、reg-notify-github-pluginreg-notify-slack-plugin を使えば以下の様に GitHub の PR や Slack へもいい感じに通知してくれます。

f:id:lulu-ulul:20180426114920p:plainf:id:lulu-ulul:20180426115429p:plain
GitHub や Slack への通知イメージ

Capybara-screenshot による画像の撮影

実は Misoca には Rubyist がたくさんいますので、RSpec で Capybara に慣れ親しんだエンジニアが多いです。

そこで Capybara + capybara-screenshotにより各画面への移動や画面操作を行い適宜スクリーンショットを撮影する様にしました。

コード的にも一連の操作が分かりやすく書けるのと、JavaScript の実行もできるので Capybara DSL で詰まった時に力技で回避できるのも良いですね。

苦労した所

スクリーンショットベースでの比較になるため、描画してから撮影されるまでの時間で表示が変わるアニメーションする要素が天敵です。

スタイルによるアニメーションも当然なのですが、 テキストボックスのキャレットも点滅するため差分が生じてしまいます。 ピクセル数や画面内の面積比率で閾値を設定する事もできるのですが、これらを解消して閾値をより低めに設定しておきたい所です。

そこでスクリーンショットの撮影前や適宜 execute_script で以下の処理を行う様にしました。

  • キャレットを非表示するために caretColortransparent に変更
  • headtransition-property / transform / animation を無効にする style タグを追加

検出結果のサンプル

この様な形式でレポートが作成され、差分があった画像は前後の画像と差分画像が出力されます。

f:id:lulu-ulul:20180427123603p:plain

差分をオーバーレイした画像とは別に、差分のあった領域を囲って表示してくれるので確認しやすくなっています。

f:id:lulu-ulul:20180427120941p:plain

この様に目視での判別が難しい細かな差分も検出されます

f:id:lulu-ulul:20180427124957p:plainf:id:lulu-ulul:20180427104446p:plain
目視では判別の難しい差分

まとめ

以上の方針でビジュアルテストが平日に実行される様にできました。

プロジェクトの期間もあったのでスコープから外したのですが、以下にも対応してもっと安心して開発していける様にしたいですね。

  • 現在は headless chrome のみでのテストなので、デザイン崩れが起きやすい他のブラウザでの実行もサポートする
  • CI / 開発環境でもテストできる様にする

Misocaでは安心してリリース / リファクタリングできる開発環境の構築に興味のあるエンジニアを募集しています!