ビジュアルリグレッションテスト(Visual Regression Test)とは
ビジュアルリグレッションテスト(以下、VRT)は、画像回帰テストとも呼ばれます。
VRTは、改修による予期せぬ UI のデザイン崩れを検出することを目的としています。
UIのスクリーンショットを撮り、それらをコミット間で比較して、変更を特定します。
Storybookの運用イメージ
当社のReactを利用したプロジェクトではデザインシステムの構築にStorybookを利用しています。
細かい運用はこの記事では割愛しますが、見た目上のバリエーションが存在するコンポーネントについては、1つのコンポーネントにつき下記の2画面を用意するようにしています。
Basic: StorybookのControlsアドオンを利用して動作確認できる
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で動かすためのタスクを追加します。
{
...
"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の設定ファイルです。
のコマンドでひな形を生成することができます。
{
"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を確認できるようにしています。
module.exports = {
...
addons: [
...
'storycap', // addonとして、storycapを追加
...
],
...
}
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の株式会社プレセナ・ストラテジック・パートナーズエンジニア公式アカウントで発信しています。ご確認ください。