Storybookを利用したビジュアルリグレッションテスト

ビジュアルリグレッションテスト(Visual Regression Test)とは

ビジュアルリグレッションテスト(以下、VRT)は、画像回帰テストとも呼ばれます。

VRTは、改修による予期せぬ UI のデザイン崩れを検出することを目的としています。 UIのスクリーンショットを撮り、それらをコミット間で比較して、変更を特定します。

Storybookの運用イメージ

当社のReactを利用したプロジェクトではデザインシステムの構築にStorybookを利用しています。 細かい運用はこの記事では割愛しますが、見た目上のバリエーションが存在するコンポーネントについては、1つのコンポーネントにつき下記の2画面を用意するようにしています。

  • Basic: StorybookのControlsアドオンを利用して動作確認できる

  • All: バリエーションが一覧できる

VRTの導入手順

多くのツールが存在しますが、プレセナでは下記のツールを利用しています。 以下、VRTを導入していく手順を紹介します。

導入するツール

  • StorycapStorybookをクロールし、スクリーンショット画像を取得します。

  • 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_IDAWS_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の株式会社プレセナ・ストラテジック・パートナーズエンジニア公式アカウントで発信しています。ご確認ください。

最終更新