Claude CodeでChromaticのビジュアルテストを回す — PRの差分検知とHooks連携
Claude CodeでStorybookを編集しながらChromaticのビジュアルテストを回す手順です。GitHub ActionsでのPR差分検知と、Stopフックによる自動実行を組み合わせます。
ChromaticはStorybookのコンポーネントを対象にしたビジュアルリグレッションテストのクラウドサービスです。Claude CodeでUIコンポーネントとストーリーを編集する開発フローに組み込むと、見た目の崩れをPRの段階で検知できます。本記事では、Chromaticの基本セットアップからGitHub ActionsでのPR連携、Claude CodeのStopフックで自動実行する構成までを扱います。
Chromaticとは何か
Chromaticとは、Storybookのストーリーごとにクラウドブラウザでスクリーンショットを撮影し、直前のビルドと比較してUIの差分を検出するサービスです。開発元はStorybookチームで、Storybookと同じ設計思想で作られています。Storybookを使っていない場合でも、Vitest・Playwright・Cypressのテストをビジュアルリグレッションテストに変換する形で連携できます。
差分が見つかると、レビュアーは変更を承認(Accept)するか却下(Deny)するかを選びます。承認した変更は次回以降の比較基準(ベースライン)として更新され、却下した変更はビルドを失敗させます。この承認フローがPull Requestの「UI Tests」ステータスチェックと連動する点が、ChromaticをCIに組み込む主な理由です。
導入前に確認する前提条件
Chromaticを使うにはいくつかの前提条件があります。Storybook 6.5以降が必要で、公式にサポートされているNodeのバージョンは18・20・21です。それ以外のNodeバージョンではエラーが出ることがあります。
Gitリポジトリであることも必須です。Chromaticはコミット履歴を辿ってベースラインを決めるため、GitHub・GitLab・Bitbucketのいずれかでホストされたリポジトリか、それらに対応していないGitホストを使う場合は「Unlinked」プロジェクトとして設定します。Unlinkedプロジェクトでは自動のPRステータスチェックが付かず、CI側で個別に設定する必要があります。
Chromatic CLIをセットアップする
1. サインアップしてプロジェクトを作成する
GitHub・GitLab・Bitbucket、またはメールアドレスでChromaticにサインインし、新しいプロジェクトを作成します。プロジェクトごとに一意のプロジェクトトークンが発行され、このトークンをCLIやCI設定に渡します。
2. CLIをインストールする
npm install --save-dev chromaticpackage.jsonにスクリプトを追加しておくと、以降はnpm run chromaticで実行できます。
{
"scripts": {
"chromatic": "chromatic"
}
}このスクリプトは環境変数CHROMATIC_PROJECT_TOKENからトークンを読み取ります。CI環境ではリポジトリのシークレットとして設定するのが安全です。
3. 初回ビルドでベースラインを作る
npx chromatic --project-token <your-project-token>初回ビルドは各ストーリーのスナップショットを撮影し、それをベースラインとして保存します。以降のビルドは、このベースラインと新しいスナップショットを比較して差分を検出します。
差分をレビューしてPRをマージする
Claude CodeでStorybookのストーリーやコンポーネントを編集したあとにChromaticビルドを実行すると、変更前後のスクリーンショットがビルド画面に並びます。各差分について、承認すればその見た目が新しいベースラインになり、却下すればビルドは失敗扱いになります。
すべての変更を承認するとビルドはPassの状態になり、GitHub・GitLab・BitbucketのPRに付く「UI Tests」ステータスチェックも緑になります。マージ後、承認済みのベースラインはターゲットブランチのストーリーにも適用されるため、同じ変更を二度承認する必要はありません。レビュアーは特定のスナップショットにディスカッションを紐づけてコメントすることもでき、バグの指摘とビジュアル差分の却下を組み合わせて、マージ前に修正を促す運用ができます。
GitHub ActionsでPRごとに自動実行する
手元でのnpx chromaticだけでなく、CIでpushごとにビルドを走らせておくと、レビュアーがPR上で常に最新の差分を確認できます。.github/workflows/chromatic.ymlに以下のワークフローを追加します。
name: "Chromatic"
on: push
jobs:
chromatic:
name: Run Chromatic
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-node@v7
with:
node-version: 24.20.0
- name: Install dependencies
run: npm ci
- name: Run Chromatic
uses: chromaui/action@latest
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}fetch-depth: 0は必須です。デフォルトのshallow cloneではコミット履歴が足りず、Chromaticがベースラインの祖先コミットを見つけられずにビルドが失敗します。
PRごとの差分検知を高速化するには、TurboSnapを有効にします。onlyChanged: trueを追加すると、webpackの依存関係グラフをもとに変更のあったストーリーだけを再テストし、大規模なStorybookでもビルド時間を抑えられます。
- name: Run Chromatic
uses: chromaui/action@latest
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
onlyChanged: trueCIのステータスチェック自体をブロッキングにしたい場合はexitZeroOnChanges: falseを追加します。デフォルトではChromaticは差分があっても終了コード0を返し、レビュー判断はPR上の「UI Tests」バッジに委ねられます。このオプションをfalseにすると、未レビューの差分があるだけでワークフローのジョブ自体が失敗します。
Claude CodeのStopフックでビジュアルテストを自動化する
Claude Codeにストーリーファイルの編集を任せている場合、編集のたびに手動でnpx chromaticを叩くのは手間です。Claude Codeのフックを使うと、編集内容に応じてビルドを自動実行できます。どのイベントに紐づけるかで運用の重さが変わります。
| フックイベント | おすすめ度 | 理由 |
|---|---|---|
| Stop(ターン終了時に1回) | おすすめ度◎ | 理由1回の指示で編集した複数のストーリーをまとめてビルドでき、クラウドビルドの回数を抑えられる |
| PostToolUse(Edit/Writeごと) | おすすめ度△ | 理由ストーリーを1つ直すたびにビルドが走り、待ち時間とビルド消費数が増えやすい |
| PreToolUse | おすすめ度✕ | 理由Chromaticのビルドは非同期で結果が出るまで数十秒かかるため、ツール実行前のブロック判断には向かない |
Stopイベントはツール名によるmatcherの絞り込みに対応していないため、フックはセッションのターンが終わるたびに毎回起動します。スクリプト側でgit status --porcelainを使い、ストーリーファイルの変更があるときだけビルドを実行する形にします。
.claude/hooks/chromatic-stop-check.shを作成します。
#!/bin/bash
INPUT=$(cat)
# Stopフックが既に継続実行中なら再度ビルドしない(無限ループ防止)
STOP_HOOK_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active')
if [ "$STOP_HOOK_ACTIVE" = "true" ]; then
exit 0
fi
CHANGED_STORIES=$(git status --porcelain | grep -E '\.stories\.(tsx|jsx|ts|js)$')
if [ -z "$CHANGED_STORIES" ]; then
exit 0
fi
BUILD_LOG=$(npx chromatic --project-token "$CHROMATIC_PROJECT_TOKEN" --exit-zero-on-changes 2>&1)
BUILD_URL=$(echo "$BUILD_LOG" | grep -oE 'https://www\.chromatic\.com/build\?appId=[^[:space:]]+')
cat <<JSON
{
"hookSpecificOutput": {
"hookEventName": "Stop",
"additionalContext": "Chromaticビルドを実行しました。差分レビュー: ${BUILD_URL}"
}
}
JSONchmod +x .claude/hooks/chromatic-stop-check.sh.claude/settings.jsonにフックを登録します。
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/chromatic-stop-check.sh"
}
]
}
]
}
}stop_hook_activeを見ずにビルドを実行すると、フックがClaude Codeを継続させるたびに再度ビルドが走り、Claude Codeが8回連続でブロックされた時点で強制的に停止させられます。この確認は省略しないほうが安全です。additionalContextで渡した内容はStop hook feedbackとしてトランスクリプトに表示され、Claudeはビルド結果のURLをそのままユーザーへの報告に使えます。
よくあるつまずき
git log -n 1のエラーでビルドが失敗する
ChromaticはGit履歴をもとにコミットとPRを紐づけるため、実行環境にgitコマンドが無いと失敗します。Dockerコンテナでベースイメージにgitが入っていない、Heroku CIでデフォルトではGit履歴が渡されない、Google Cloud CIで.gitフォルダが既定で無視される、といったケースでよく起きます。CI環境のイメージにgitを含めるか、Git履歴へのアクセスを別途許可します。
「祖先ビルドが見つからない」と表示される
fetch-depth: 0を指定せずshallow cloneのままChromaticを実行すると、直前のビルドの祖先コミットが履歴上に存在せず、このエラーになります。チェックアウトステップでフル履歴を取得するよう設定を見直します。
ERR_INVALID_ARG_TYPEが出る
PlaywrightやCypressのプロジェクトで、package.jsonのoverridesに"storybook": "$storybook"のような指定が残っていると、ChromaticがPlaywright/Cypressと非互換なStorybookバージョンを使ってしまい、このエラーになります。Storybookのoverrides指定を削除すると解消します。
PRのステータスチェックが更新されない
Unlinkedプロジェクトとして作成した場合、ChromaticはGitホストへの自動投稿権限を持たないため、「UI Tests」バッジは自動で付きません。GitHub・GitLab・Bitbucketと連携したプロジェクトに切り替えるか、CI側でコミット/PRのステータスを自分で更新する設定が必要です。
まとめ
Chromaticの導入自体は、サインアップ・CLIインストール・初回ビルドの3ステップで完了します。ここにpushイベントでのGitHub Actions連携とTurboSnapを組み合わせれば、PRごとに変更のあったストーリーだけを検証できます。Claude Codeでの編集をビルドにつなぐ部分は、Stopフックでgit statusを見て変更があるときだけ実行する構成が、コストと見落としのバランスを取りやすい形です。ストーリーの生成やプレビュー自体をClaude Codeに任せる場合は、Storybook MCPサーバーをClaude Codeに繋ぐ手順と組み合わせると、コンポーネント生成からビジュアルテストまでの一連の流れをエージェントに任せやすくなります。Hooksの設定パターン全般はClaude Code Hooks完全ガイドとClaude Code Hooks実例カタログにまとまっています。CIへの組み込み方をさらに広げたい場合はClaude CodeをGitHub Actionsに組み込む手順も参考になります。