playwright-verify について
playwright-verify は、Playwright の単独スクリプトと Node.js で一時的なブラウザ確認を行うスキルです。テストランナーを用意せずにローカルやファイルのページを検証し、ブラウザ・ネットワークのエラー確認や UI 要素の計測ができます。
主な機能
- 01単独の .mjs 検証スクリプトの実行
- 02ページのスクリーンショット撮影
- 03コンソール・ページ・HTTP・リクエストのエラー収集
- 04要素の寸法とスタイルの計測
- 05CDP によるブラウザー状態の維持
活用シーン
- 01ブラウザーツールがアクセスできない localhost ページの検証
- 02表示されない、またはクリックできない要素の調査
- 03テストスイートを作らずにコードの仮説を確認
- 04ブラウザーセッションを維持した複数ステップの確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ rheinmir/ setup --skill playwright-verifyインストール後、Claude Code で/playwright-verifyを入力して読み込まれたか確認します。
詳細
スキル:playwright-verify
GH#96 から得た知見です。安価(1回あたり < 5s、LLM 不要)な検証ツールであり、このマシンで claude-in-chrome が localhost と file:// の2つのスキームをブロックしている場合に、これらとやり取りする唯一の方法です。
WHAT
目的とコンテキスト
- 目的: standalone の
.mjsとnode(テストランナーなし)で Playwright を実行し、コードを素早く1回だけ検証します。localhost/file://のスクリーンショットを撮影し、console/pageerror/http/requestfailed のエラーを取得し、実際の要素を測定して、認証をバイパスします。複数ステップの作業には、永続セッションのconnectOverCDPを使います。 - 使用するタイミング:
localhost:*/file://でclaude-in-chromeがFrame with ID 0 is showing error pageまたはCan't interact with browser-internal or unparseable URLsと表示する場合。- UI 要素が「見えない」/「クリックできない」原因を診断する必要がある場合。スクリーンショットだけでは不十分で、実際の数値(
getBoundingClientRect、getComputedStyle)が必要です。 - コードの仮説を1つだけ検証して破棄する場合(
*.spec.tsとテストランナーを作成するほどではない場合)。 - 毎回実際に SSO ログインする代わりに、dev-login/偽セッション経由でテストする必要がある場合。
- ユーザーが「Playwright で検証」「ページを撮影」「スクリプトで UI を素早くテスト」「複数ステップを検証」「実行間でセッションを維持」「クリックできない/要素が見えない」または
/playwright-verifyと指定した場合。
- ユーザーが「Playwright で検証」「ページを撮影」「スクリプトで UI を素早くテスト」「複数ステップを検証」「実行間でセッションを維持」「クリックできない/要素が見えない」または
- 対象外:
*.spec.tsとテストランナー(npx playwright test)は作成しません。UAT テストケース集ではありません(→ uat-nonit-testcase)。通常の外部ウェブページでclaude-in-chromeの代わりに使うものではありません。スクリプトを対象リポジトリにコミットしません。
メンタルモデル
検証する仮説 →(インストール済み?)→ 使い捨ての .mjs スクリプト:起動 → 4つのエラーチャネルを接続 → goto(読み込み + 待機)→ スクリーンショット/測定 → 終了 → ログ + 画像を確認 → 破棄。複数ステップの分岐:専用 Chrome CDP(使い捨てプロファイル)← 各 step-N.mjs が接続し、状態は実行間で維持 → 終了時に pkill
入力と出力の契約
| Field | Required? | 意味 | |
|---|---|---|---|
| In | URL(localhost:* / file:// / その他) | はい | 検証するページ |
| In | node_modules に @playwright/test があるプロジェクト | はい | スクリプトはそのディレクトリから実行する必要があります(または NODE_PATH を使用) |
| In | dev-login の cookie/localStorage | いいえ | 認証をバイパスするため |
| Out | スクリーンショット(例:/tmp/check.png)+ [console]/[pageerror]/[http]/[reqfail] ログ | はい | 証拠です。画像がきれいなだけでは不十分です |
| Out | getBoundingClientRect/getComputedStyle の測定値 | 要素の診断時 | 画像からの推測ではなく、実際の数値 |
| Out | 「完了」 | — | ログ + 画像で仮説を確認または否定し、スクリプトをクリーンアップ済みです。Chrome CDP(使用した場合)も pkill 済みです |
ルールと機能
- RULE-01 (MUST):
import { chromium } from "@playwright/test"は、@playwright/testがnode_modulesにあるプロジェクトディレクトリ内から実行する必要があります。ESM はスクリプトファイルの場所ではなく、cwdに基づいて解決します。別のディレクトリ(例:/tmp)にあるスクリプトは、実行前にプロジェクトへcpするか、NODE_PATHを指定してください。 - RULE-02 (MUST):Next.js の開発サーバーでは
waitUntil: "networkidle"が無期限に停止します。HMR/webpack dev が long-poll/websocket 接続を常時維持するため、ネットワークが「idle」になることはありません。waitUntil: "load"と固定のpage.waitForTimeout(N)を使ってください。 - RULE-03 (MUST):dev-login の認証をバイパスする方法:
context.addCookies([{url, name, value}])(domainとpathを個別に指定するよりurlを優先してください。Cookie が一致しなくなるのを防げます)と、context.addInitScript(...)によるlocalStorageの設定を使います。newPage()を呼ぶ前に状態を設定してください。呼び出した後ではありません。 - RULE-04 (MUST):独立した各ルートに対して
contextを1つずつ使ってください。アプリに「補助 API で 401 が発生すると、セッション全体を自動的に削除する」ロジックがある場合、複数のナビゲーションで1つの context を使い回すと、ルート N のエラーがルート N+1 に伝播します。 - RULE-05 (MUST):「見えない/クリックできない」場合の診断:スクリーンショットだけを見て判断しないでください。
page.evaluate(() => el.getBoundingClientRect())とgetComputedStyle(el)を呼び出して実際の数値を取得します。locator.click()は明確なエラー(「element is not visible」など)と再試行の手順のログを出すので、原因を推測する前にそのログを確認してください。 - RULE-06 (MUST):きれいなスクリーンショットは何の証明にもなりません。エラーの4つの経路を必ずすべて確認してください。2つだけでは不十分です。
console(typeerror)·pageerror·status() >= 400のresponse·requestfailed。Analytics のクラッシュ、API の 5xx、promise の拒否は、ピクセルには現れません。gotoの前にpageへ登録してください:page.on("response", r => { if (r.status() >= 400) console.log("[http]", r.status(), r.url()); }); page.on("requestfailed", r => console.log("[reqfail]", r.failure()?.errorText, r.url())); - RULE-07 (MUST):セッションを保持するモードでは、専用の Chrome と専用のプロファイルを使ってください(一時的な
--user-data-dir)。ユーザー個人の Chrome で--remote-debugging-portを使うことは絶対に避けてください。macOS では許可を求めるダイアログが表示され、スクリプトがユーザーの作業中のタブに干渉します。 - RULE-08 (MUST):スタンドアロンのスクリプトを git に追加しないでください。scratchpad から実行し、対象リポジトリにはコミットしないでください。
- RULE-09 (MUST):タスクで必要な箇所だけを変更し、ついでの変更は行わないでください。
- 機能:ローカルでのヘッドレスブラウザーの実行と一時ファイルの読み書き。外部ネットワークへのアクセスは、バイナリのインストール(CDN)時にタイムアウト付きでのみ行います。
失敗時の対応範囲
npx playwright installがネットワークでブロックされる、または停止する → ブロック状態として、タイムアウトを含む明確なエラーを報告し、コマンドを無期限に停止させないでください。- ESM が
@playwright/testを解決できない(誤ったcwdで実行)→ スクリプトをプロジェクトに cp するかNODE_PATHを指定して、再実行してください。 - Next.js の開発環境で
networkidleが停止する →loadとwaitForTimeoutに切り替えてください(アプリのエラーではありません)。 - 要素が見えない/クリックできない → 実際の数値を測り、
locator.click()のログを確認してから判断してください。画像だけから推測しないでください。
方法
メインワークフロー
| ステップ | 種類 | 入力 | アクション | 出力/終了 | 失敗時/次の処理 |
|---|---|---|---|---|---|
| W01 | 決定的 | マシン | インストール済みか確認(ls ~/Library/Caches/ms-playwright)。未インストールならインストール | バイナリ準備完了 | CDN がブロックされている → blocked |
| W02 | 判断 | 仮説 + URL | node で直接実行できる .mjs ファイルを 1 つ作成し、goto の前に 4 つのエラーチャネルを設定 | スクリプト | — |
| W03 | 実行 | スクリプト | 正しいディレクトリから実行(node check.mjs)し、ログと画像を確認。スクリプトを削除 | ログ + 画像 | エラーを解決 → cp/NODE_PATH、W03 を繰り返す |
| W04 | 実行 | 複数ステップの作業 | 永続セッションモード connectOverCDP(B01) | 状態を次のターンまで維持 | 完了 → pkill |
各ステップの詳細(W01〜W04 の正確な情報源):
- 再インストールする前に、インストール済みかどうかを確認します:
ls ~/Library/Caches/ms-playwright(macOS)— バイナリキャッシュはすべてのプロジェクトで共有されるため、リポジトリごとに再インストールする必要はありません。- 未インストールの場合:
pnpm add -D @playwright/test(プロジェクトのdevDependenciesにすでに含まれている場合は省略)を実行し、その後npx playwright install chromiumを実行します。 npx playwright installは外部 CDN(cdn.playwright.dev)からバイナリをダウンロードします。ネットワークの許可リストを使用するサンドボックス/CI では、停止したままになるか失敗します。自動実行する場合はタイムアウトを設定し、ブロックされた場合はコマンドを無期限に停止させず、明確にエラーを報告してください。
- 未インストールの場合:
nodeで直接実行できる.mjsファイルを 1 つ作成します(npx playwright testは使いません)。確認して破棄する用途には、こちらのほうが適しています:import { chromium } from "@playwright/test"; // export chromium dùng được như package "playwright" const browser = await chromium.launch(); const page = await browser.newPage({ viewport: { width: 1400, height: 900 } }); page.on("console", m => console.log("[console]", m.type(), m.text())); page.on("pageerror", e => console.log("[pageerror]", e.message)); await page.goto("http://localhost:3000/some-page", { waitUntil: "load" }); // KHÔNG "networkidle" — xem Rules #2 await page.waitForTimeout(1500); await page.screenshot({ path: "/tmp/check.png", fullPage: true }); await browser.close();- 正しいディレクトリから(Rules #1 を参照)、
node check.mjsを実行し、コンソール/pageerror のログとスクリーンショットを確認します。特定のプロジェクト内で実行した場合は、完了後に.mjsファイルを削除します(scratch dir から実行した場合、git から削除する必要はありません。スクリプトはリポジトリ内にありません)。 - 条件付きの複数ステップの作業には、永続セッションモードを使います(browser-use/browser-harness から学んだ方法、09/2026)。一度だけ実行するスクリプトでは、エージェントがシナリオ全体を見通しなしに書くことになります。1 つでもステップを間違えると、ログインからやり直しです。代わりに、CDP ポートを使う Chrome を 1 つ起動し、各ターンでそれに接続する小さなスクリプトを実行します。タブ、Cookie、
localStorage、スクロール位置がターン間で維持されるため、エージェントは状況を確認してから次のステップを決められます。# một lần — Chrome riêng, profile riêng; KHÔNG bám vào Chrome cá nhân của user CH="$HOME/Library/Caches/ms-playwright/chromium-1243/chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing" "$CH" --remote-debugging-port=9333 --user-data-dir=/tmp/pw-prof --headless=new --no-first-run about:blank &// mỗi lượt — step-N.mjs import { chromium } from "@playwright/test"; const browser = await chromium.connectOverCDP("http://localhost:9333"); const ctx = browser.contexts()[0]; const page = ctx.pages()[0] ?? await ctx.newPage(); // bám tab cũ, KHÔNG launch mới // ... một hành động + quan sát; state sống sang lượt sau ... await browser.close(); // chỉ ngắt kết nối, Chrome vẫn chạy
作業が終わったら、pkill -f "remote-debugging-port=9333" を実行します。
09/09/2026 の計測結果(python-playwright、同じ file:// ページ):新規起動は 1 ターンあたり 1.1〜1.9 秒で、状態は失われます。connectOverCDP は 1 ターンあたり 0.65〜0.80 秒で、新しいプロセスを起動しても window.__marker が維持されました(3/3)。上記の .mjs 版は計測セッションで node を使って実行していません。API は実行済みの Python 版と同じです。
分岐
| ID | 種類 | 条件 | 動作 | スキップ/失敗 | 再開 |
|---|---|---|---|---|---|
| B01 | 条件付き必須 | 条件付きの複数ステップの作業(状況を確認してから次のステップを決める必要がある) | --remote-debugging-port=9333 と一時プロファイルを指定した専用の Chrome を 1 つ起動し、各ターンで step-N.mjs から connectOverCDP を使って接続 | 一度だけ実行する作業 → スキップ。個人用 Chrome には絶対に接続しない | pkill -f "remote-debugging-port=9333" で終了 |
| B02 | ユーザー任意 | 開発用ログイン/偽セッションが必要なページ | newPage() の前に context.addCookies と context.addInitScript を実行します。アプリが 401 時にセッションを自動削除する場合は、ルートごとに 1 つの context を使います | — | W03 |
| B03 | 復旧 | 要素が「見つからない/クリックできない」 | page.evaluate(() => el.getBoundingClientRect()) と getComputedStyle(el) を使い、locator.click() の再試行ログを確認します | — | W03 |
検証と停止
結論は、4 つのエラーチャネル、画像、計測値に基づいて出し、画像だけで判断しません。各ターンは 5 秒未満で、LLM は使いません。仮説が証拠によって裏付けられた時点で停止します。スクリプトを削除し、CDP の Chrome を pkill で終了します。
例
- 成功例: claude-in-chrome が
http://localhost:3000/some-pageでFrame with ID 0 is showing error pageを報告 →check.mjsをプロジェクトに cp →node check.mjsを実行 →/tmp/check.pngと、[console]/[pageerror]/[http]/[reqfail]のすべてがクリーンなログを取得 → ページのレンダリングを確認し、スクリプトを削除します。 - 境界条件/失敗例: Next.js の開発環境で
waitUntil: "networkidle"を使うスクリプト → 無期限に停止します。waitUntil: "load"+page.waitForTimeout(1500)に変更すると、正常に完了します。画像がクリーンでも、ログに[http] 500 /api/xがあれば、合格と報告してはいけません。