代理店の悪夢:「200 OK」だけでは不十分な理由
午前3時の電話
それはすべての代理店CTOが恐れるシナリオです。金曜日の午後にアップデートをリリースしました。CI/CDパイプラインはすべてグリーン。単体テストもパス。統合テストもパス。Sentryは例外ゼロを示しています。
しかし、土曜日の朝、あなたの最大のクライアントからパニック状態で電話がかかってきます。
「1時間前にキャンペーンを開始したんだけど、顧客から支払いができないと言われている。『今すぐ購入』ボタンがクリックできないんだ。」
あなたは急いでノートパソコンに向かいます。サーバーは 200 OK を返しています。APIは50msで応答しています。しかし、ページをロードしてそれを見つけます。グローバルCSSの更新による z-index の変更が原因で、Cookie同意バナーがチェックアウトボタンの上に 目に見えない状態で 重なっていたのです。
ボタンはそこにあります。ロジックは機能しています。しかし、ユーザーにとっては、サイトは壊れています。
これが「従来のモニタリング」が失敗し、「ビジュアルモニタリング」が重要になるギャップです。
なぜ単体テストは視覚的なバグを見逃すのか
エンジニアとして、私たちはコードレベルのテストに大きく依存しています。APIをモックし、コンポーネントのロジックをテストし、クラッシュをチェックします。
// 典型的なテスト:ロジックが機能するかを確認するが、ユーザーがそれを使えるかは確認しない
test('checkout flows', async () => {
const result = calculateTotal(cart);
expect(result).toBe(100);
// パスする。たとえ結果が白地に白のテキストでレンダリングされていても。
});しかし、Webアプリケーションは視覚的に不安定です。共有されたTailwindユーティリティクラスのたった一つの変更や、予期せぬブラウザのアップデートが、Javascriptエラーを一つも出さずにレイアウトを破壊することがあります。
「静かな」失敗
- CSSの衝突: 2つのライブラリ間の詳細度(Specificity)の争い。
- アセットの失敗: 画像がリンク切れアイコンとして読み込まれ、レイアウトが50px上にずれる。
- レスポンシブの癖: 特定のiPhoneの幅でテキストが折り返され、CTAが折り目の下に押しやられる。
解決策:自動化されたビジュアルリグレッション
ぐっすり眠るためには、コードプローブだけでなく、サイトに対する目が必要です。ここで ビジュアルリグレッションテスト の出番です。
概念はシンプルです:
- 「ゴールデンマスター」(正しい状態)の スナップショット を撮る。
- デプロイごと、または定期的に新しいスナップショットを撮る。
- ピクセルを比較する。
差分がしきい値を超えた場合、チームにアラートを送ります。
Playwrightを使った基本的なチェックの実装
Playwrightのようなツールを使って独自のソリューションを構築できます:
import { test, expect } from '@playwright/test';
test('homepage should look correct', async ({ page }) => {
await page.goto('https://client-site.com');
// これが視覚的な状態をキャプチャします
await expect(page).toHaveScreenshot('home-desktop.png', {
maxDiffPixels: 100 // わずかなレンダリングノイズを許容
});
});しかし、これを50のクライアントサイトにスケールさせるには、新たな課題が伴います。数千の画像のストレージコスト、誤検知(動的広告、カルーセル)の処理、そして信頼性の高いスケジューリングインフラストラクチャのセットアップです。
ループを閉じる
代理店において、あなたの評判こそが製品です。クライアントは、バックエンドがRustで書かれていることや、テストカバレッジが100%であることなど気にしません。彼らが気にするのは、彼らの顧客が物を買えるかどうかです。
ビジュアルモニタリングは、「コードの正しさ」と「ユーザーエクスペリエンス」の間のギャップを埋めます。それは、クライアントが見る前に恥ずかしい事態をキャッチします。
Is your site visually healthy?
Don't guess. Run a deeper visual scan right now and catch hidden bugs before your users do.