React + Vite + Storybook の環境構築
まずは、React + Vite + Storybook の環境を構築します。
npm create vite@latest . -- --template react-ts
npm install
npx storybook@latest init --builder vite
今回は、Storybook が作成してくれた Story(src/stories/*)を元に、VRT を行います。
Storycap の導入
Storycap は、Storybook をクロールし、スクリーンショットを撮影するライブラリです。
まずは必要なパッケージをインストールします。
npm install -D storycap
次に、Storybook の設定に Storycap を追加します。
.storybook/main.ts
const config: StorybookConfig = {
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
addons: [
"@storybook/addon-onboarding",
"@storybook/addon-links",
"@storybook/addon-essentials",
"@chromatic-com/storybook",
"@storybook/addon-interactions",
"storycap"
],
// ...
parameters.screenshot.viewports には、desktop
, tablet
, mobile
の 3 つのビューポートを指定しています。
これにより、各デバイス幅での UI 崩れも検知することができます。
その他の設定はこちらを参照してください。
.storybook/preview.ts
import type { Preview } from "@storybook/react";
import { withScreenshot } from "storycap";
export const decorators = [
withScreenshot,
];
const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
screenshot: {
fullPage: false,
delay: 0,
viewports: {
desktop: { width: 1920, height: 1080 },
tablet: { width: 768, height: 1024 },
mobile: { width: 360, height: 800, isMobile: true, hasTouch: true },
},
},
},
};
export default preview;
最後に .gitignore に__screenshots__
を追加し、Storycap の設定は完了です。
.gitignore
# storycap
__screenshots__
動作確認
下記コマンドを実行して、プロジェクト直下に__screenshots__
ディレクトリが作成されていることを確認してください。
npx storycap http://localhost:6006 --serverCmd 'storybook dev -p 6006'
__screenshots__
ディレクトリには、各 Story のスクリーンショットが保存されています。
また、viewports を 3 種類指定しているので、1 つの Story ごとに 3 つのスクリーンショットが撮影されているはずです。
reg-suit の導入
次に reg-suit を導入します。
reg-suit は、画像の差分を検知し、差分を画像として保存することができるライブラリです。
まずは画像の保存先として、S3 バケットを作成しておきます。
保存先の S3 バケットの作成
実際にプロジェクトで運用する場合は、CloudFront などを利用して関係者のみがアクセスできるようにする方が良いですが、今回は VRT のお試しなので、設定の簡略化のために、誰でもアクセスできるようにしておきます。
CloudFrontなどを利用して関係者のみがアクセスできるようにする
に関しては、また別途記事にまとめたいと思います。
AWS コンソールから S3 バケットを作成します。
バケット名はユニークである必要があるので、適当な名前をつけてください。
オブジェクト所有者はACL有効
にしておきます。
ブロックパブリックアクセス設定は、全てのチェックを外しておいてください。
また S3 にアクセスするための IAM ユーザーを作成し、アクセスキーとシークレットアクセスキーを取得しておいてください。
reg-suit のインストール
事前準備が完了したので、下記コマンドを実行してインストールします。
npm install -D reg-suit
インストールが完了したら、初期設定を行います。
npx reg-suit init
質問がいくつか表示されるので、以下のように回答してください。
? Plugin(s) to install (bold: recommended) (Press <space> to select, <a> to toggle all, <i> to invert selection, and
<enter> to proceed)
❯◉ reg-keygen-git-hash-plugin : Detect the snapshot key to be compare with using Git hash.
◉ reg-notify-github-plugin : Notify reg-suit result to GitHub repository
◉ reg-publish-s3-plugin : Fetch and publish snapshot images to AWS S3.
◯ reg-notify-chatwork-plugin : Notify reg-suit result to Chatwork channel.
◯ reg-notify-github-with-api-plugin : Notify reg-suit result to GHE repository using API
◯ reg-notify-gitlab-plugin : Notify reg-suit result to GitLab repository
◯ reg-notify-slack-plugin : Notify reg-suit result to Slack channel.
? Working directory of reg-suit. .reg
? Append ".reg" entry to your .gitignore file. Yes
? Directory contains actual images. __screenshots__
? Threshold, ranges from 0 to 1. Smaller value makes the comparison more sensitive. 0
? notify-github plugin requires a client ID of reg-suit GitHub app. Open installation window in your browser Yes # ブラウザが立ち上がるので、対象のリポジトリを選択してインストールして、ClientIDを取得してください
? This repositoriy's client ID of reg-suit GitHub app ○○○○ # ○○○○には、取得したClientIDを入力してください
? Bucket name ○○○○ # ○○○○には、事前に作成したS3バケット名を入力してください
? Update configuration file Yes
? Copy sample images to working dir No
次に、package.json に以下のスクリプトを追加します。
package.json
"scripts": {
"ci:screenshot":"npx storycap http://localhost:6007 --serverCmd 'npx http-server storybook-static --ci -p 6007'",
"ci:vrt":"npx reg-suit run"
},
GitHub Actions での自動化
最後に、GitHub Actions で VRT を自動化します。
GitHub のリポジトリのシークレットに、事前に取得しておいた アクセスキー(AWS_ACCESS_KEY_ID
)とシークレットキー(AWS_SECRET_ACCESS_KEY
)を登録しておいてください。
ワークフローを作成します。
プロジェクト直下に.github/workflows/vrt.yml
を作成し、以下の内容を記述してください。
.github/workflows/vrt.yml
name: visual regression testing
on: [push]
jobs:
vrt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: |
git fetch --prune --unshallow
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Use Node.js v20
uses: actions/setup-node@v4
with:
node-version: "20"
- name: npm install, build, and test
run: npm install
- name: workaround for detached HEAD
run: |
git checkout ${GITHUB_REF#refs/heads/} || git checkout -b ${GITHUB_REF#refs/heads/} && git pull
- name: storybook build
run: npm run build-storybook
- name: screenshot and visual regression test
run: |
npm run ci:screenshot
npm run ci:vrt
おつかれさまでした!これで実装は完了です。
動作確認
動作確認を行いましょう!
現在の変更をmainブランチ
にコミットします。
まずは、UI に変更がないパターンを見てみましょう。
新しいブランチ
を作成して、src/components/Page.tsx
にid を追加して、main ブランチへのプルリクエストを作成します。
src/components/Page.tsx
22 <section className="storybook-page">
23 <h2 id='title'>Pages in Storybook</h2>
プルリクエストをすると、VRT が実行され、結果を reg-suit が以下のようにコメントで教えてくれます!
次に、UI に変更があるパターンを見てみましょう。
また別のブランチ
を作成して、src/components/Page.tsx
からStorybook
のテキストを削除して、main ブランチへのプルリクエストを作成します。
src/components/Page.tsx
22 <section className="storybook-page">
23 <h2>Pages in</h2>
すると以下のようにコメントされます!
コメントの中の赤丸は、差分があった画像の数を表しています。
青丸は差分がなかった画像の数を表しています。
その他に、白丸は削除された画像の数、ただの丸は追加された画像の数を表しています。
this report
をクリックすると、レポートを確認することができます!
レポートには、差分画像が表示されているので、どこが変更されたのかを確認することができます。
レポートで変更内容に問題がない事を確認してから、マージを行います。
これで、VRT の自動化が完了しました!
詰まった点
Github Actions での自動化の際に、比較元の画像を取得できずに、毎回新規追加された画像として扱われてしまう問題が発生しました。
出力としては、warn Failed to detect the previous snapshot key
と毎回表示されていました。
この問題に関して、以下のサイトが参考になりました。
git fetch --prune --unshallow
を追加することで、解決しました。
.github/workflows/vrt.yml
- uses: actions/checkout@v4
- run: |
git fetch --prune --unshallow
さいごに
VRTを導入すると、予期せぬ UI 崩れを検知することができるので、安心して開発を進めることができます。
ぜひ、導入してみてください!