CSSの変更やUIライブラリのアップデート後、意図しない見た目の崩れに気づかず本番リリースしてしまった経験はないでしょうか。数百ページにおよぶUIの差分を人の目だけで確認するのは現実的ではありません。ビジュアルリグレッションテスト(Visual Regression Testing、略称VRT)は、スクリーンショットの画像比較によってUIの意図しない変化を自動検出するテスト手法です。

VRTの定義と動作の流れ

VRTは、変更前後のUIスクリーンショットをピクセル単位で照合し、差分が生じた箇所をハイライト表示する仕組みです。一般的な実行フローは次の4ステップで構成されます。

  1. ベースライン撮影 — テスト対象ページやコンポーネントのスクリーンショットを基準画像として保存します
  2. コード変更後に再撮影 — 同一条件でスクリーンショットを再取得します
  3. ピクセル差分比較 — 基準画像と新画像を自動照合し、閾値を超える差分を検出します
  4. 差分レポート生成 — 変更前・変更後・差分の3枚セットで結果を可視化します

検出にはピクセル単位の色差比較(Pixel Diffing)が主流です。CSSの1px変更やフォントレンダリングの微妙な差異も捉えられるため、人間の目視チェックでは見逃しやすい変化を確実に検出できます。

DOMスナップショットテストとの相違点

VRTと混同されやすい手法にDOMスナップショットテストがあります。両者には次の違いがあります。

比較項目VRT(画像比較)DOMスナップショットテスト
比較対象レンダリング済みの画像シリアライズされたDOM構造
検出範囲CSS変更・レイアウト崩れ・フォント差異DOM構造・属性値の変更
実装への依存度低い(表示結果だけを検証)高い(内部構造に依存)
偽陽性の傾向環境差分(OS・フォント)で発生しやすいリファクタリングで壊れやすい
差分の視認性画像で直感的に確認できるテキスト差分の解読が必要

DOMスナップショットテストは、class名やHTML構造を変更しただけで見た目に影響がなくてもテストが失敗します。VRTは「ユーザーが実際に目にする表示結果」だけを検証するため、リファクタリング時の不要なテスト失敗を減らせる点が大きな利点です。

VRTが威力を発揮する場面

VRTはフロントエンドテスト戦略のなかで、特に次のような状況で効果的です。

  • UIライブラリのバージョンアップ — Material UIやChakra UIなどのメジャーアップデート時に、全コンポーネントの外観変化を一括検証できます
  • CSSリファクタリング — グローバルスタイルの変更が他のページに波及していないか確認できます
  • レスポンシブ対応 — 複数のビューポートサイズで同時にスクリーンショットを撮影し、レイアウト崩れを発見できます
  • ダークモード対応 — カラースキーム切替時の全画面チェックを自動化できます
  • システムリプレース・移行 — 旧環境と新環境の画面を並べて差分を検証でき、移行時の品質担保に役立ちます

主要VRTツール7選の機能・費用一覧【2026年版】

VRTツールはOSS型(自前運用)とSaaS型(クラウドサービス)に大別されます。プロジェクト規模・予算・技術スタックに応じて最適なツールは異なります。

ツール種別無料枠有料プラン(税別・月額)Storybook連携対応ブラウザCI統合
PlaywrightOSS完全無料△(別途設定)Chromium / Firefox / WebKitGitHub Actions等
reg-suit + StorycapOSS完全無料ChromiumGitHub Actions等
ChromaticSaaS5,000枚/月$179〜(35,000枚)◎(公式)Chrome / Safari / Firefox / EdgeGitHub / GitLab / Bitbucket
Percy(BrowserStack)SaaS5,000枚/月要問合せChrome / Firefox主要CI全般
Argos CISaaS5,000枚/月$100〜(35,000枚)ChromiumGitHub / GitLab
BackstopJSOSS完全無料×Chromium(Puppeteer/Playwright)主要CI全般
Lost PixelOSS+SaaSOSS無料ありChromiumGitHub Actions

各ツールの価格は2026年2月時点の公式サイト情報に基づきます(出典: Chromatic / 出典: Percy / 出典: Argos CI)。

なお、CypressでもVRTは可能ですが、公式にはスクリーンショット比較機能を内蔵していないため、cypress-image-diff-jsなどのサードパーティプラグインが必要です。Playwrightのように組み込みのVRT APIが用意されているわけではない点に注意してください。

ツール選定の判断基準

Storybookを運用中の場合 — ChromaticまたはReg-suit + Storycapが最小工数で導入できます。Chromaticは差分レビュー用のWebUIが充実しており、チームでの承認フローに強みがあります。コストを抑えたい場合はreg-suitにAWS S3やGoogle Cloud Storageを組み合わせる構成が有効です(出典: reg-suit公式)。

E2Eテストも兼ねたい場合 — PlaywrightのtoHaveScreenshot()が最適です。ページ遷移やユーザー操作を伴うシナリオでスクリーンショットを取得でき、追加ライブラリが不要です。

大規模プロジェクトでコスト効率を重視する場合 — Argos CIはProプランで追加スナップショット単価が$0.004と比較的低く、Playwrightトレースの再生やflaky検出を備えています。

Storybook未導入でURL単位の比較をしたい場合 — BackstopJSはJSON設定ファイルだけで運用を始められ、導入のハードルが低い選択肢です。

PlaywrightによるVRT導入手順

Playwrightにはテストフレームワーク組み込みのVRT機能(toHaveScreenshot())があります。追加ライブラリなしでVRTを実行できるため、Playwright VRTの導入手順を具体的なコードとともに示します。

1. インストール

npm init playwright@latest

初期セットアップウィザードが起動し、テストディレクトリの作成やブラウザのダウンロードが行われます。既存プロジェクトへの追加は次のコマンドでも可能です。

npm install -D @playwright/test
npx playwright install chromium

2. 基本的なVRTコード

// tests/visual.spec.ts
import { test, expect } from '@playwright/test';

test('トップページの外観', async ({ page }) => {
  await page.goto('http://localhost:3000');
  await expect(page).toHaveScreenshot('top-page.png');
});

初回実行時は基準画像が存在しないためテストが失敗し、test-results/ディレクトリにスクリーンショットが保存されます。次のコマンドで基準画像を確定させます。

npx playwright test --update-snapshots

2回目以降は基準画像と新しいスクリーンショットが自動比較され、差分があればテストが失敗します。

3. 要素単位の比較

ページ全体ではなく特定要素だけを比較すると、ヘッダーやフッターの変化に左右されない安定したテストが書けます。

test('ナビゲーションバーの外観', async ({ page }) => {
  await page.goto('http://localhost:3000');
  const nav = page.locator('nav.main-navigation');
  await expect(nav).toHaveScreenshot('navbar.png');
});

4. 閾値とオプションの設定

環境差分によるノイズを抑えるために、差分の許容量をplaywright.config.tsで設定できます。

// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  expect: {
    toHaveScreenshot: {
      // 差分ピクセル比率の上限(全体の0.5%まで許容)
      maxDiffPixelRatio: 0.005,
      // 色差の閾値(0が厳密、1が寛容)
      threshold: 0.2,
    },
  },
});

maxDiffPixelsで絶対ピクセル数を指定する方法もあります。フォントレンダリングの差異が出やすい環境ではthresholdを0.2〜0.3程度にすると偽陽性を抑えられます。

5. 複数ビューポートでのレスポンシブテスト

const viewports = [
  { width: 375, height: 812, name: 'mobile' },
  { width: 768, height: 1024, name: 'tablet' },
  { width: 1440, height: 900, name: 'desktop' },
];

for (const vp of viewports) {
  test(`トップページ - ${vp.name}`, async ({ page }) => {
    await page.setViewportSize({ width: vp.width, height: vp.height });
    await page.goto('http://localhost:3000');
    await expect(page).toHaveScreenshot(`top-${vp.name}.png`);
  });
}

6. GitHub Actionsでの自動実行

Pull Requestごとに自動でVRTを走らせるワークフロー例です。

# .github/workflows/vrt.yml
name: Visual Regression Test

on:
  pull_request:
    branches: [main]

jobs:
  vrt:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - run: npx playwright test --reporter=html
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: vrt-report
          path: playwright-report/
          retention-days: 14

差分が発生した場合はArtifactsからHTMLレポートをダウンロードし、差分画像を確認できます。

Storybook連携によるコンポーネント単位のVRT

Storybookを導入済みのプロジェクトでは、各Storyを自動キャプチャしてVRTを行う方法が効率的です。

Chromaticを使う方法

Chromaticは、Storybookのクラウドホスティングとスクリーンショット差分検出を統合したSaaSです。

npm install -D chromatic
npx chromatic --project-token=<YOUR_TOKEN>

CIのワークフローに1ステップ追加するだけで、PRごとに全Storyのスクリーンショットが比較されます。差分が検出されるとChromaticのWebUI上で承認・却下の操作が可能です。無料プランでは月5,000スナップショットまで利用できます(出典: Chromatic公式)。

reg-suit + Storycapを使う方法

OSSで運用コストを抑えたい場合は、reg-suit(画像比較・レポート生成)とStorycap(Storybookスクリーンショットの自動撮影)の組み合わせが定番です。

npm install -D storycap reg-suit
npx reg-suit init

スクリーンショットの保存先としてAWS S3やGoogle Cloud Storageを設定し、GitHubのPRにレポートリンクをコメントする運用が一般的です。reg-suitはプラグインシステムを採用しており、通知先(GitHub PR、Slack)やストレージを柔軟に選べます(出典: reg-suit GitHub)。

VRT運用で押さえるべき実践ポイント

動的コンテンツとアニメーションの制御

日時表示・ランダム広告・CSSアニメーションなどの動的要素は、テスト実行ごとに異なるスクリーンショットを生成し、偽陽性(False Positive)の原因になります。主な対処法は3つです。

要素のマスキング — Playwrightのmaskオプションで変動する要素を隠します。

await expect(page).toHaveScreenshot('page.png', {
  mask: [page.locator('.ad-banner'), page.locator('.timestamp')],
});

CSSアニメーションの停止 — テスト実行前にスタイルを注入し、すべてのアニメーションとトランジションを無効化します。

await page.addStyleTag({
  content: `*, *::before, *::after {
    animation: none !important;
    transition: none !important;
  }`,
});

日時の固定page.clock APIやモックライブラリで日時を固定し、表示の揺れを防ぎます。

OS・フォント差異の吸収

macOSとLinuxではフォントレンダリングが異なるため、ローカルで撮影した基準画像がCI環境(ubuntu-latest等)で一致しないケースがあります。対策としてはDockerコンテナ内でテストを実行する方法が確実です。CI上で基準画像を生成・管理する運用にすると環境差分を回避できます。

テスト実行時間の短縮

StoryやページのVRT対象が増えると実行時間が課題になります。次の工夫で短縮できます。

  • 影響範囲のみテスト — NxやTurborepoのaffectedコマンドで、変更パッケージに関連するテストだけを実行する方法があります
  • 並列実行 — PlaywrightのworkersオプションやCIのmatrix strategyで並列化し、合計時間を削減します
  • 対象Storyの絞り込み — タグやパラメータでVRT対象のStoryを限定し、不要なキャプチャを減らします

まとめ

ビジュアルリグレッションテスト(VRT)は、UIの外観変化をスクリーンショットの画像比較で自動検出するテスト手法です。CSSリファクタリングやUIライブラリ更新で生じる予期しないレイアウト崩れを、人の目に頼らず確実に捕捉できます。

Playwrightを使えば追加ライブラリなしでtoHaveScreenshot()によるVRTを始められ、GitHub Actionsとの組み合わせでPull Requestごとの自動検査も実現します。Storybookを運用しているプロジェクトではChromaticやreg-suitとの連携で、コンポーネント単位の精密な検証が可能です。

ツール選定ではチームの規模・予算・Storybookの有無・CI環境を軸に、本記事の比較表から最適な組み合わせを選ぶと導入がスムーズです。