ビジュアルリグレッションテスト(Visual Regression Test)とは
ビジュアルリグレッションテスト(以下、VRT)は、画像回帰テストとも呼ばれます。
VRTは、改修による予期せぬ UI のデザイン崩れを検出することを目的としています。
UIのスクリーンショットを撮り、それらをコミット間で比較して、変更を特定します。
Storybookの運用イメージ
当社のReactを利用したプロジェクトではデザインシステムの構築にStorybookを利用しています。
細かい運用はこの記事では割愛しますが、見た目上のバリエーションが存在するコンポーネントについては、1つのコンポーネントにつき下記の2画面を用意するようにしています。
- Basic: StorybookのControlsアドオンを利用して動作確認できる
- All: バリエーションが一覧できる
VRTの導入手順
多くのツールが存在しますが、プレセナでは下記のツールを利用しています。
以下、VRTを導入していく手順を紹介します。
導入するツール
- Storycap: Storybookをクロールし、スクリーンショット画像を取得します。
- reg-suit: 画像の差分をレポートとして出力してくれます。
- reg-keygen-git-hash-plugin: 比較すべきコミットを特定します。
- reg-notify-github-plugin: GitHubのPRにレポートを通知します。
- reg-publish-s3-plugin: 差分レポートをS3にアップロードします
これらのツールを組み合わせることで、Pull Requestにテスト結果の通知が届くようになります。
通知内のリンクから、さらに詳細なレポートを確認することもできます。
package.jsonの記述
yarnやnpmを利用して、パッケージのインストールをおこなってください。
npm-scriptsにも、CIで動かすためのタスクを追加します。
package.json
{ ... "scripts": { "build-storybook": "build-storybook", "ci:vrt": "reg-suit run", "ci:storybook-generate": "build-storybook -c .storybook -o dist-storybook -s public", "ci:storycap": "storycap --serverTimeout 60000 --captureTimeout 10000 --serverCmd 'npx http-server dist-storybook --ci -p 9009' http://localhost:9009", }, ... "devDependencies": { ... "reg-keygen-git-hash-plugin": "0.10.16", "reg-notify-github-plugin": "0.10.16", "reg-publish-s3-plugin": "0.10.16", "reg-suit": "0.10.16", "storybook-addon-next-router": "3.0.5", "storycap": "3.0.4", ... }, }
GitHub Actions で正常に動かなったため、タスクを「Storybookのビルド(ci:storybook-generate)」と「スクリーンショットの撮影(ci:storycap)」に分割しています。
storycapの公式が推奨するコマンドは下記のため、
( https://github.com/reg-viz/storycap#getting-started )
storycap --serverCmd "start-storybook -p 9001" http://localhost:9001
CIツールによっては、タスク分割せずに実行が可能かもしれません。
regconfig.jsonの記述
reg-suitの設定ファイルです。
% npx reg-suit init
のコマンドでひな形を生成することができます。
regconfig.json
{ "core": { "workingDir": ".reg", "actualDir": "__screenshots__", "thresholdRate": 0.001, "addIgnore": true, "ximgdiff": { "invocationType": "client" } }, "plugins": { "reg-keygen-git-hash-plugin": true, "reg-notify-github-plugin": { "prComment": true, "prCommentBehavior": "default", "clientId": "$REG_NOTICE_CLIENT_ID" }, "reg-publish-s3-plugin": { "bucketName": "your bucket name", "acl": "private" } } }
GitHub Actions ワークフローの記述
ワークフローをトリガーするGitHubイベントは、pull_requestではなく、pushである必要があります。
ubuntu-latestのイメージには、日本語が含まれていないため、日本語フォントインストールのジョブを入れています。Storybook上で日本語を利用していない場合は不要です。
.github/workflows/vrt.yml
name: Visual Regression Testing on: push jobs: build: runs-on: ubuntu-latest strategy: matrix: node-version: [14.x] steps: - name: Checkout uses: actions/checkout@25a956c84d5dd820d28caab9f86b8d183aeeff3d with: fetch-depth: 0 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@aa759c6c94d3800c55b8601f21ba4b2371704cb7 with: node-version: ${{ matrix.node-version }} cache: yarn - name: Japanese Font Install run: sudo apt install fonts-noto-cjk - name: Install dependencies run: yarn --frozen-lockfile - name: workaround for detached HEAD run: git checkout ${GITHUB_REF#refs/heads/} || git checkout -b ${GITHUB_REF#refs/heads/} && git pull - name: run storybook generate run: yarn run ci:storybook-generate - name: run storycap run: yarn ci:storycap - name: run reg-suit run: yarn ci:vrt env: REG_NOTICE_CLIENT_ID: ${{ secrets.REG_NOTICE_CLIENT_ID }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
REG_NOTICE_CLIENT_IDは、公式のREADMEを参考に、 GitHubにreg-suitアプリを追加して取得してください。
AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYは、regconfig.jsonに記載したbucketにアクセスできるものをIAMなどで作成してください。 ポリシーなどの詳細は、公式のREADMEを参考にしてください。
S3の細かい設定はこの記事では割愛します。
これらのID/KEYは、GitHubのsecretに登録する必要があります。
以上でVRTのために必要な設定は完了です。
画面幅の異なるスクリーンショットを撮る設定
上記の設定だけでもVRTとして正しく機能しますが、プレセナでは画面幅に応じた見た目の変化など細かくUIを確認できるようにしています。
.storybook/main.js
module.exports = { ... addons: [ ... 'storycap', // addonとして、storycapを追加 ... ], ... }
Header.stories.tsx
import React from 'react' import Header, { Props } from '@/components/organisms/Header' import { Story, Meta } from '@storybook/react' export default { title: 'Parts/Header', component: Header, parameters: { layout: 'fullscreen', }, } as Meta export const Basic: Story<Props> = (args): JSX.Element => <Header {...args} /> Basic.args = { title: 'タイトル', } // 画面幅の異なるスクリーンショットを取るための記述 Basic.parameters = { screenshot: { variants: { small: { viewport: 'iPhone 5', }, }, }, }
上記のような記述を追加することで、画像幅の異なるスクリーンショットを撮ることが可能になります。これによって、網羅性の高いテストを目指すことが可能です。
本サイトの更新情報は、Twitterの株式会社プレセナ・ストラテジック・パートナーズエンジニア公式アカウントで発信しています。ご確認ください。