こんにちは。フロントエンドエンジニアの小林和弘です。
Vue.js + Atomic Designでつくられたプロジェクトにビジュアルリグレッションテストを導入しました。
ビジュアルリグレッションテストでUIの安全性を高める
コンポーネントの改修、新機能の追加、ライブラリのアップデートを行う際、UIに不要な変更が入っていないか不安になることがあると思います。リファクタリングをしようにも、意図しないところでUIが壊れないか心配になります。
画面表示に関わるコードを改修するたびに、ローカル環境やステージング環境で全UIコンポーネントを確認するのは難しいです。
また、ステージング環境と本番環境を並べて変更されたUIを目視で確認するのも非現実的です。
ビジュアルリグレッションテストはその名前の通り、視覚的な回帰テストを指します。改修前後のスクリーンショットの差分を検証するためのテストです。
開発におけるUIの安全性を高め、安心してUI改善を行えるようにビジュアルリグレッションテストの導入を行いました。
使用したツール
- reg-suit
- ビジュアルリグレッションテストのためのテスティングツール
- 差分レポートを作成してくれる
- GitHubへのPull Request通知機能があり、PR毎にUI差分が見れる
- Storybook
- UIコンポーネントのカタログを作成する
- 実装済のUI、UIパターンをすぐに確認できる
- 画面上でコンポーネントの挙動把握ができる
- アドオンが豊富でデバイスサイズ変更時のUI表示確認などができる
- Storycap
- Storybookから各コンポーネントのスクリーンショットを作成する
- reg-suitと同じGitHub Organizationのreg-viz内で管理されている
Storybookの導入
まずは比較画像の元となるStorybookを導入します。
インストール用のnpm@storybook/cli
が提供されているのでnpx
コマンドでインストールをします。
今回はVue.jsプロジェクトに導入するのでtype
オプションにvue
を設定します。
$ npx -p @storybook/cli sb init --type vue
インストール時に行われるのは
- Storybookと依存モジュールのインストール
- StorybookのAddonのインストール
- npm scriptsにStorybookを実行するスクリプト追加
- storiesディレクトリの追加
- 設定ファイルを格納する.storybookディレクトリの追加
になります。
storiesディレクトリ内にはサンプルのStoryファイルとVueコンポーネント(Welcome, MyButton)が格納されています。
package.jsonにはstorybook
, build-storybook
が追加されます。
{ "scripts": { "storybook": "start-storybook -p 6006", "build-storybook": "build-storybook" } }
storybookを実行するとnpm scriptsに設定されたポート番号 6006
でStorybookが立ち上がります。
$ yarn storybook
Storycapの導入
次にStorybookに登録されたStoryのスクリーンショットを作成して、reg-suitで画像の比較ができるようにしていきます。
スクリーンショット作成のためにStorycapをインストールします。
$ yarn add storycap --dev
次に.storybook/config.js
を作成して、StorybookのAddonとしてStorycapを登録します。
今回はVue.jsのプロジェクトなので@storybook/vue
からaddDecorator
を呼び出しています。
import { addDecorator } from '@storybook/vue'; import { withScreenshot } from 'storycap'; addDecorator(withScreenshot);
package.json
にStorycapを実行するnpm scriptsを追加します。
{ "scripts": { "screenshot": "storycap --serverCmd \"start-storybook -p 6006\" http://localhost:6006" } }
実際にコマンドを実行すると、__screenshots__
ディレクトリにスクリーンショットが保存されます。
スクリーンショット画像はバージョン管理に含める必要がないので.gitignore
に追記してGitの管理下から外しておきます。
__screenshots__
reg-suitの導入
まずreg-suitをインストールします。
$ yarn add reg-suit --dev
次にローカルのreg-suit initコマンドを実行します。対話形式でreg-suitの設定ができます。
$ yarn reg-suit init
Plugin(s) to install (bold: recommended)
使用するプラグインを選択します。
今回は下記の3つを選択しています。
- reg-keygen-git-hash-plugin : Gitの親ブランチの元ハッシュと、現在のブランチのハッシュを比較する
- reg-notify-github-plugin : GitHub AppでPull Requestにコメントをつける
- reg-publish-s3-plugin : AWS s3にスクリーンショットとテストのレポートをアップロードする
Working directory of reg-suit. => .reg
テストの結果を出力するディレクトリを指定します。デフォルトの.reg
ディレクトリのままで問題ありません。
Append ".reg" entry to your .gitignore file. => Yes
reg-suitの出力結果はAWS s3で管理するので、Gitの管理下から外すためYesにします。
Directory contains actual images. => __screenshots__
テストに利用する画像のディレクトリを指定します。
Storycapのデフォルト値の__screenshots__
を指定します。
Threshold, ranges from 0 to 1. Smaller value makes the comparison more sensitive. => 0
テストの差分比較の閾値を設定します。
厳密に差分検知をしたい場合は0を指定します。
notify-github plugin requires a client ID of reg-suit GitHub app. Open installation window in your browser => Yes
GitHub Appのreg-suitの登録を行います。
reg-suitの設定ページがブラウザで開くので、ビジュアルリグレッションを導入したいリポジトリを選択します。
Client IDをクリップボードにコピーしておきます。
This repositoriy's client ID of reg-suit GitHub app => {Client ID}
GitHub AppのページでコピーしたClient IDを設定します。
Create a new S3 bucket => No
AWSにログイン済みでs3の作成権限があればYesにしてbucketの作成を行います。
権限がなかったので今回はNoで回答しました。
Existing bucket name => ***
s3のBucketが作成済みの場合、ここでbucket名を設定します。
Update configuration file => Yes
ここまで回答した設定を、設定ファイルのregconfig.json
に反映します。
Copy sample images to working dir => No
サンプル画像のコピーは不要なのでNoで回答します。
以上でreg-suitの設定が完了です。
次にpackage.json
のnpm scriptsにreg-suitのコマンドを追記します。
{ "scripts": { "regression": "reg-suit run" } }
AWS s3の権限があればローカル実行で動作します。
$ yarn regression
CircleCIの設定
GitHubのリモートブランチへpushした時に自動でテストを実行するために、CIの設定を追記します。
今回使用しているのはCircleCIです。
GitHubアカウントでCircleCIにログインして、Projectsから対象のプロジェクトを選択します。
プロジェクト選択後、Project Settings > Environment VariablesからAWS s3のAccess Key IDとSecret Access Keyを設定します。
reg-suitコマンドではデフォルトでAWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
変数を参照するようになっています。
別の変数名を定義したい場合(今回は仮にREGRESSION_ACCESS_KEY
, REGRESSION_SECRET_KEY
)、npm scriptsのregressionで変数を代入しておきましょう。
{ "scripts": { "regression": "AWS_ACCESS_KEY_ID=$REGRESSION_ACCESS_KEY; AWS_SECRET_ACCESS_KEY=$REGRESSION_SECRET_KEY; reg-suit run" } }
次にCircleCIの設定ファイルconfig.yml
にJOBを追加します。
jobs: visual_regression: steps: - checkout - restore_cache: name: Restore node_modules key: yarn-{{ checksum "yarn.lock" }}-{{ .Environment.CACHE_VERSION_NPM }} - run: name: Install dependencies command: yarn install - save_cache: name: Cache node_modules key: yarn-{{ checksum "yarn.lock" }}-{{ .Environment.CACHE_VERSION_NPM }} paths: - ~/workspace/node_modules - run: name: install jp fonts command: sudo apt-get install fonts-ipafont-gothic fonts-ipafont-mincho - run: name: screenshots command: yarn screenshot - run: name: regression command: yarn regression --quiet
デフォルトでは日本語フォントがTofuになってしまうため、IPAフォントをインストールしています。
実際に使う
実際にGitHub上でPRを作成するとCircleCI上でvisual_regressionが実行され、完了したらキャプチャ画像のような結果レポートのコメントが追加されます。
this reportのリンクをクリックすると、s3にアップロードされた差分比較ができるページに遷移します。
差分があった場合、もしくは新規でスクリーンショットが追加された場合、reg-suitのチェックが失敗します。
レビュアーがreg-suitのPRのコメントやレポートを確認して問題がないか確認します。
UI変更に問題があった場合はPR上でUIの修正を進めます。
UIの変更に問題がなければ、Approveをします。Approveするとreg-suitのチェックがパスするようになります。
まとめ
Storybook + reg-suitによるビジュアルリグレッション導入はこれで完了です。
やっていることとしては
- StorybookでUIのカタログを作成
- StorycapでStorybookのスクリーンショットを作成
- reg-suitでGitのブランチ間のスクリーンショットの比較レポートを作成
- reg-suitのGitHub AppでPR上にコメントを通知
になります。
実際に非レスポンシブなサイトを部分的にレスポンシブ対応する際にビジュアルリグレッションテストでUI破壊をいくつか検知でき、その恩恵を受けることができました。
意図しないUI破壊を防ぐためにビジュアルリグレッションテストを導入しましたが、大元となるのはStorybookに登録されたStoryです。
なのでStorybookのメンテナンスを怠るとテストが形骸化してしまいます。
Storybookはメンテナンスコストが高く、導入が難しいという意見もあります。しかしStorybookによるUIのカタログ化は、メンテナンスコストを差し引いても大きなメリットがあると考えています。
ビジュアルリグレッションテストのスクリーンショットに利用できるだけではなく、実装済みUIの再実装を未然に防いだり、Storybook上でコンポーネントの動作を確認しながらUI開発ができたり、Addonを使ってレスポンシブ表示を確認できたりと様々なメリットがあります。
この記事で皆様の安全なUI管理に少しでも貢献できれば幸いです。
メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!
■募集ポジションはこちら
https://medpeer.co.jp/recruit/entry/
■開発環境はこちら
https://medpeer.co.jp/recruit/workplace/development.html