From d698b9dc7d1f6fcc9cdf77cc8aabd2bd923047df Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Tue, 26 May 2026 02:43:01 +0000 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20playwright-browser-connect=20/=20pl?= =?UTF-8?q?aywright-evidence-drive=20Skill=20=E8=BF=BD=E5=8A=A0=20(v4.10.0?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - playwright-browser-connect: ローカル Chromium / Windows CDP / macOS CDP の 3 パターン対応 - playwright-evidence-drive: テストエビデンス一式の Google Drive 保管・共有 - config.py に BrowserConfig dataclass 追加 (mode: local|cdp-remote) - scenario.config.yaml に browser: セクション追加 - conftest.py.template に connect_over_cdp() 対応 browser fixture 追加 - 関連 Skill の参照リンクを更新 Co-Authored-By: Claude Opus 4.7 (1M context) --- plugins/ndf/.claude-plugin/plugin.json | 6 +- .../playwright-browser-connect/SKILL.md | 261 ++++++++++++++++++ .../skills/playwright-evidence-drive/SKILL.md | 188 +++++++++++++ .../ndf/skills/playwright-execution/SKILL.md | 2 + .../ndf/skills/playwright-kit-ops/SKILL.md | 1 + .../playwright_kit/config.py | 29 ++ .../templates/conftest.py.template | 21 ++ .../templates/scenario.config.yaml | 13 + plugins/ndf/skills/playwright-report/SKILL.md | 8 +- .../skills/playwright-scenario-test/SKILL.md | 2 + 10 files changed, 528 insertions(+), 3 deletions(-) create mode 100644 plugins/ndf/skills/playwright-browser-connect/SKILL.md create mode 100644 plugins/ndf/skills/playwright-evidence-drive/SKILL.md diff --git a/plugins/ndf/.claude-plugin/plugin.json b/plugins/ndf/.claude-plugin/plugin.json index 4a249f5..084911d 100644 --- a/plugins/ndf/.claude-plugin/plugin.json +++ b/plugins/ndf/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "ndf", - "version": "4.9.0", - "description": "Integrated plugin with 8 specialized agents (model-tiered: opus/sonnet/haiku), 44 skills including official mcp-builder, on-demand loader for Anthropic official skills, generic workflow/principle skills, skill usage statistics, pytest-playwright E2E testing split into 5 focused skills (test-planning, script-creation, execution, report, kit-ops) + orchestrator with video-by-default evidence, Google Drive/Chat integration, and Codex CLI integration via /ndf:codex skill. Transcript retention is automatically kept at >= 90 days. Serena MCP is a separate plugin (mcp-serena).", + "version": "4.10.0", + "description": "Integrated plugin with 8 specialized agents (model-tiered: opus/sonnet/haiku), 46 skills including official mcp-builder, on-demand loader for Anthropic official skills, generic workflow/principle skills, skill usage statistics, pytest-playwright E2E testing split into 7 focused skills (test-planning, script-creation, execution, report, kit-ops, browser-connect, evidence-drive) + orchestrator with video-by-default evidence, CDP remote browser support, and Google Drive evidence archival, Google Drive/Chat integration, and Codex CLI integration via /ndf:codex skill. Transcript retention is automatically kept at >= 90 days. Serena MCP is a separate plugin (mcp-serena).", "author": { "name": "takemi-ohama", "url": "https://github.com/takemi-ohama" @@ -66,6 +66,8 @@ "./skills/playwright-execution", "./skills/playwright-report", "./skills/playwright-kit-ops", + "./skills/playwright-browser-connect", + "./skills/playwright-evidence-drive", "./skills/playwright-scenario-test", "./skills/google-drive", "./skills/google-chat", diff --git a/plugins/ndf/skills/playwright-browser-connect/SKILL.md b/plugins/ndf/skills/playwright-browser-connect/SKILL.md new file mode 100644 index 0000000..8cbdd0e --- /dev/null +++ b/plugins/ndf/skills/playwright-browser-connect/SKILL.md @@ -0,0 +1,261 @@ +--- +name: playwright-browser-connect +description: "Playwright E2E テストのブラウザ接続先を構成する。ローカル Chromium / Windows リモート Chrome (CDP) / macOS リモート Chrome (CDP) の 3 パターンをサポートし、scenario.config.yaml の browser: セクションで宣言的に切り替える。" +when_to_use: "E2E テストのブラウザ接続先を設定・変更するとき / remote Chrome に CDP で接続したいとき / WSL2 Docker から Windows Chrome を操作したいとき / macOS ホストの Chrome を使いたいとき。Triggers: 'ブラウザ接続', 'remote chrome', 'CDP接続', 'connectOverCDP', 'リモートブラウザ', 'Windows Chrome', 'macOS Chrome', 'browser connect', 'cdp endpoint', 'remote debugging'" +allowed-tools: + - Read + - Bash +--- + +# Playwright Browser Connect (ブラウザ接続構成) + +E2E テスト実行時のブラウザ接続先を構成する。 + +## 接続モード一覧 + +| モード | scenario.config.yaml | 接続先 | 用途 | +|---|---|---|---| +| `local` | `browser.mode: local` | コンテナ内 Chromium | CI / ヘッドレス実行 (デフォルト) | +| `cdp-remote` | `browser.mode: cdp-remote` | リモート Chrome (CDP) | GUI 操作・ログイン済み Session 再利用 | + +## 設定 (scenario.config.yaml) + +```yaml +# --- ブラウザ接続設定 -------------------------------------------------- +browser: + # local: playwright install chromium でインストールしたローカルブラウザ (デフォルト) + # cdp-remote: Chrome DevTools Protocol 経由でリモートブラウザに接続 + mode: local + + # cdp-remote 時のみ有効 + cdp_endpoint: ${CDP_ENDPOINT:-ws://localhost:9222} +``` + +## パターン別セットアップ + +### パターン 1: ローカルコンテナ Chromium (デフォルト) + +設定不要。`run.sh` 初回実行時に `playwright install chromium` が自動実行される。 + +```yaml +browser: + mode: local +``` + +### パターン 2: Windows ホスト Chrome (WSL2 + Docker → CDP) + +WSL2 上の Docker コンテナから Windows 側の Chrome GUI を CDP 経由で操作する。 + +#### 構成図 + +``` +Docker container (playwright) + ↓ ws://host-gateway:9223 +WSL2 host + ↓ portproxy or Node proxy +Windows host + ↓ localhost:9222 +Chrome (--remote-debugging-port=9222) +``` + +#### セットアップ手順 + +**Step 1: Windows Chrome をリモートデバッグモードで起動** + +```powershell +# Windows PowerShell +& "C:\Program Files\Google\Chrome\Application\chrome.exe" ` + --remote-debugging-port=9222 ` + --user-data-dir="C:\tmp\chrome-debug" +``` + +既存プロファイルのログイン済み Session を使う場合: + +```powershell +# 全 Chrome プロセスを閉じてから +& "C:\Program Files\Google\Chrome\Application\chrome.exe" ` + --remote-debugging-port=9222 +``` + +**Step 2: Node.js Proxy (9223 → 9222) を設置** + +Chrome CDP の WebSocket は `Host` ヘッダ検証があるため、直接ポートフォワードでは接続できない。 +Node.js proxy で `Host` を書き換える。 + +```javascript +// proxy.js (Windows 側に配置) +const net = require("net"); +const server = net.createServer((client) => { + const chrome = net.connect(9222, "127.0.0.1", () => { + client.pipe(chrome); + chrome.pipe(client); + }); + chrome.on("error", () => client.destroy()); + client.on("error", () => chrome.destroy()); +}); +server.listen(9223, "0.0.0.0", () => { + console.log("CDP proxy listening on 0.0.0.0:9223 → 127.0.0.1:9222"); +}); +``` + +```powershell +node proxy.js +``` + +**Step 3: WSL2 .wslconfig (NAT mode 確認)** + +```ini +# %USERPROFILE%\.wslconfig +[wsl2] +networkingMode=NAT +``` + +**Step 4: Docker Compose で host-gateway を設定** + +```yaml +# docker-compose.yml +services: + app: + extra_hosts: + - "host-gateway:host-gateway" +``` + +**Step 5: scenario.config.yaml** + +```yaml +browser: + mode: cdp-remote + cdp_endpoint: ${CDP_ENDPOINT:-ws://host-gateway:9223} +``` + +環境変数で指定する場合: + +```bash +export CDP_ENDPOINT="ws://host-gateway:9223" +``` + +### パターン 3: macOS ホスト Chrome (Docker → CDP) + +macOS 上の Docker コンテナから macOS 側の Chrome GUI を CDP 経由で操作する。 + +#### 構成図 + +``` +Docker container (playwright) + ↓ ws://host.docker.internal:9222 +macOS host + ↓ localhost:9222 +Chrome (--remote-debugging-port=9222) +``` + +#### セットアップ手順 + +**Step 1: macOS Chrome をリモートデバッグモードで起動** + +```bash +/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \ + --remote-debugging-port=9222 \ + --user-data-dir="$HOME/tmp/chrome-debug" +``` + +既存プロファイルのログイン済み Session を使う場合: + +```bash +# 全 Chrome プロセスを終了してから +/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \ + --remote-debugging-port=9222 +``` + +**Step 2: scenario.config.yaml** + +macOS Docker Desktop は `host.docker.internal` を標準サポートしているため proxy 不要。 + +```yaml +browser: + mode: cdp-remote + cdp_endpoint: ${CDP_ENDPOINT:-ws://host.docker.internal:9222} +``` + +## conftest.py への統合 + +`browser.mode: cdp-remote` の場合、pytest-playwright の通常のブラウザ起動をバイパスし、 +`connectOverCDP()` で既存 Chrome に接続する fixture を有効化する必要がある。 + +`scenario-test/conftest.py` に以下を追加: + +```python +import pytest +from playwright.sync_api import Browser, BrowserType + +@pytest.fixture(scope="session") +def browser(browser_type: BrowserType, pwk_config) -> Browser: + """browser.mode に応じてブラウザ接続を切り替える。 + + - local: pytest-playwright デフォルト (chromium.launch()) + - cdp-remote: chromium.connect_over_cdp(endpoint) + """ + browser_cfg = pwk_config.browser + if browser_cfg.mode == "cdp-remote": + browser = browser_type.connect_over_cdp(browser_cfg.cdp_endpoint) + yield browser + browser.close() + else: + # local mode: pytest-playwright デフォルトに委譲 + # (この fixture を定義しないのと同等) + browser = browser_type.launch() + yield browser + browser.close() +``` + +## run.sh での利用 + +`cdp-remote` モード時は `playwright install chromium` が不要。 +`run.sh` は初回セットアップで `playwright install` を実行するが、 +接続先がリモートの場合はスキップして問題ない (ローカルブラウザは使わないため)。 + +CDP 接続テストを手動確認する場合: + +```bash +# エンドポイントの疎通確認 +curl -s http://host-gateway:9223/json/version | python3 -m json.tool +``` + +## トラブルシュート + +### 共通 + +| 症状 | 原因 | 対策 | +|---|---|---| +| `connect_over_cdp` で接続拒否 | Chrome が起動していない / ポートが違う | `curl http:///json/version` で確認 | +| WebSocket handshake 失敗 | Host ヘッダ不一致 | Node proxy 経由に変更 | +| ページ操作が異常に遅い | VPN / DNS 解決の遅延 | `extra_hosts` で IP 直指定 | + +### Windows (WSL2) 固有 + +| 症状 | 原因 | 対策 | +|---|---|---| +| `host-gateway` 解決不能 | Docker Compose の `extra_hosts` 未設定 | `extra_hosts: ["host-gateway:host-gateway"]` を追加 | +| IPv6 でバインドされる | WSL2 が IPv6 優先 | proxy.js で `0.0.0.0` を明示 | +| `netsh portproxy` で接続ループ | portproxy の自己参照 | Node proxy に切り替え | +| mirrored mode で動かない | mirrored は localhost 共有だが CDP の WS 接続でポート競合 | NAT mode に戻す | + +### macOS 固有 + +| 症状 | 原因 | 対策 | +|---|---|---| +| `host.docker.internal` 解決不能 | Docker Desktop が古い / Linux Docker | `--add-host=host.docker.internal:host-gateway` を指定 | +| ファイアウォールでブロック | macOS のアプリファイアウォール | システム設定 > ネットワーク > ファイアウォール で Chrome を許可 | + +## CDP 接続のメリット + +- **GUI Chrome をそのまま操作可能** — OBS 録画可、人間と AI の協調操作が可能 +- **ログイン済み Session の再利用** — Google / AWS / Slack 等の MFA 済み Session をそのまま使える +- **ブラウザ拡張機能が有効** — テスト時にも拡張機能の影響を確認可能 +- **AI Agent との相性** — Claude Code / Browser Use / OpenHands がリアルブラウザを操作 + +## 関連 Skill + +- `/ndf:playwright-execution` — テスト実行 + エビデンス収集 +- `/ndf:playwright-kit-ops` — プロジェクト初期化 / ツール群 +- `/ndf:playwright-scenario-test` — 全機能統括 +- `/ndf:docker-container-access` — Docker コンテナアクセス一般 diff --git a/plugins/ndf/skills/playwright-evidence-drive/SKILL.md b/plugins/ndf/skills/playwright-evidence-drive/SKILL.md new file mode 100644 index 0000000..1917121 --- /dev/null +++ b/plugins/ndf/skills/playwright-evidence-drive/SKILL.md @@ -0,0 +1,188 @@ +--- +name: playwright-evidence-drive +description: "Playwright E2E テスト後のエビデンス一式 (動画/trace/HAR/report.md) を Google Drive に保管し、共有リンクを生成する。自動アップロード (--pwk-drive-folder) と手動アップロード (scripts) の両方をサポート。report.md → Google Docs 変換 + Drive リンク埋め込みも対応。" +when_to_use: "テストエビデンスを Google Drive に保管・共有したいとき / テスト結果を Google Docs としてチームに配布したいとき / Drive 上のエビデンスリンクを report に埋め込みたいとき。Triggers: 'Drive にアップロード', 'Drive 共有', 'エビデンス保管', 'evidence drive', 'pwk-drive-folder', 'テスト結果共有', 'Google Drive エビデンス', 'trace アップロード', '動画アップロード', 'report を Docs に', 'エビデンス配布'" +allowed-tools: + - Read + - Bash(python *) + - Bash(uv *) +--- + +# Playwright Evidence → Google Drive 保管 + +テスト実行後のエビデンス一式を Google Drive に保管し、共有可能にする。 + +## 前提条件 + +- `/ndf:google-auth` で OAuth2 認証が完了していること (drive.file スコープ) +- テスト実行済みで `reports//` にエビデンスが存在すること + +## アップロード対象 + +| ファイル | 種別 | セキュリティ考慮 | +|---|---|---| +| `video.mp4` | テスト動画 | 画面に表示された情報が含まれる | +| `trace.zip` | Playwright Trace | DOM snapshot + 操作ログ + Cookie/localStorage | +| `request.har` | ネットワーク通信ログ | HTTP request/response body を含む場合あり | +| `report.md` | テスト結果サマリ | URL + テスト名程度 | +| `body_check.jsonl` | PHP/SSR エラー詳細 | ソースコード片を含む場合あり | +| `screenshot-*.png` | 失敗時スクリーンショット | 画面に表示された情報 | + +**セキュリティ注意**: trace.zip / HAR には認証情報 (Cookie, localStorage, Basic Auth) や +入力内容が含まれる可能性がある。アップロード先は **private folder** + **信頼できる共有相手** に限定すること。 + +## 方法 1: テスト実行時の自動アップロード + +`--pwk-drive-folder` を指定すると `pytest_sessionfinish` hook で自動アップロードされる。 + +```bash +./scenario-test/run.sh --pwk-drive-folder= +``` + +動作: +1. テスト終了後に `pytest_sessionfinish` が発火 +2. `report.md` をアップロード +3. 各テストの `trace.zip` / `*.har` / `*.mp4` / `body_check.jsonl` をアップロード +4. 全ファイルは非公開 (private) でアップロードされる + +## 方法 2: 手動アップロード (scripts) + +テスト実行後に個別にアップロードする場合。スクリプトは `playwright-kit-ops/scripts/` に配置。 + +### 単一ファイルアップロード + +```bash +cd scenario-test +uv run python scripts/upload_evidence.py reports//test_login/trace.zip \ + --kind trace \ + --parent +``` + +オプション: +- `--kind {trace|har|video|any}` — ファイル種別 (拡張子から自動判定も可) +- `--parent ` — Drive 上のアップロード先フォルダ ID +- `--public` — anyone/read 権限を付与 (trace viewer URL 生成に必要) + +### ディレクトリ一括アップロード + +```bash +uv run python scripts/gdrive_upload_dir.py reports// \ + --folder-id +``` + +ディレクトリ構造を保ったまま Drive にミラーする。 +サブフォルダも再帰的に作成される。 + +### report.md → Google Docs 変換 + +```bash +uv run python scripts/upload_md_as_gdoc.py \ + --md reports//report.md \ + --parent \ + --name "E2E テスト報告書 2026-05-26" +``` + +Markdown を Google Docs 形式に変換してアップロード。 +テーブル・リスト・見出しが Docs のネイティブ形式に変換される。 + +### Google Docs にエビデンス Drive リンクを埋め込み + +```bash +uv run python scripts/build_gdoc_with_drive_links.py \ + \ + reports// \ + --parent +``` + +1. Drive 上の `` フォルダからファイル一覧を取得 +2. `report.md` 内の相対パスリンク (`./TC-XX/trace.zip`) を Drive URL に書き換え +3. 書き換え済み Markdown を Google Docs としてアップロード + +→ チームメンバーが Docs 上で report を読みながら、エビデンスへの Drive リンクをクリックして確認できる。 + +## 推奨ワークフロー + +``` +[テスト実行] + ./scenario-test/run.sh --pwk-overlay + ↓ +[ローカル確認] + reports//report.md で結果確認 + ↓ +[Drive 一括アップロード] + uv run python scripts/gdrive_upload_dir.py reports// --folder-id + ↓ +[Docs 変換 + リンク埋め込み] + uv run python scripts/build_gdoc_with_drive_links.py reports// + ↓ +[共有] + Docs URL をチーム (Slack / Google Chat) に共有 +``` + +ワンコマンドで全てを行う場合: + +```bash +./scenario-test/run.sh --pwk-drive-folder= --pwk-overlay +``` + +## Drive フォルダ構成の推奨 + +``` +E2E テスト証跡/ ← 共有ドライブ or チームフォルダ +├── <プロジェクト名>/ +│ ├── 20260526-134500/ ← run-id (自動生成) +│ │ ├── report.md +│ │ ├── test_login/ +│ │ │ ├── video.mp4 +│ │ │ ├── trace.zip +│ │ │ └── request.har +│ │ └── test_admin_dashboard/ +│ │ ├── video.mp4 +│ │ └── trace.zip +│ └── report (Google Docs) ← build_gdoc_with_drive_links で生成 +``` + +## Trace Viewer 連携 + +`--public` でアップロードした trace.zip は Playwright Trace Viewer で直接開ける: + +```bash +uv run python scripts/upload_evidence.py reports/.../trace.zip \ + --kind trace --public --parent +``` + +出力例: +``` +playwright_trace_viewer: https://trace.playwright.dev/?trace=https%3A%2F%2Fdrive.google.com%2Fuc%3Fexport%3Ddownload%26id%3D... +``` + +この URL を共有すると、インストール不要でブラウザ上から trace を再生できる。 + +**注意**: `--public` は anyone/read を付与するため、trace 内の機密情報 (Cookie, 入力値) が +公開される。社内限定の場合は private のまま `playwright show-trace` をローカルで使うこと。 + +## トラブルシュート + +| 症状 | 原因 | 対策 | +|---|---|---| +| `google_auth スキルが見つかりません` | google-auth スキル未インストール | `GOOGLE_AUTH_SCRIPTS` env を設定、または `/ndf:google-auth` で認証セットアップ | +| `HttpError 403: insufficient permissions` | drive.file スコープ不足 | `/ndf:google-auth` で再認証 (`drive.file` スコープ指定) | +| `HttpError 404: File not found` | FOLDER_ID が間違っている / アクセス権なし | Drive で共有フォルダ ID を確認 | +| `resumable upload failed` | ファイルサイズが大きい / ネットワーク不安定 | 再試行。動画は mp4 (H.264) で容量を抑える | +| pytest 後に自動アップロードされない | `--pwk-drive-folder` 未指定 | CLI 引数を確認 | + +## 環境変数 + +| 変数 | 用途 | 例 | +|---|---|---| +| `GOOGLE_AUTH_SCRIPTS` | google-auth スキルの scripts/ パス | `~/.claude/skills/google-auth/scripts` | +| `PWK_DRIVE_FOLDER` | デフォルトの Drive アップロード先 (将来対応予定) | `1ABCxyz...` | + +## 関連 Skill + +- `/ndf:playwright-execution` — テスト実行 + エビデンス収集 (Drive アップロードの前段) +- `/ndf:playwright-report` — Markdown レポート生成 +- `/ndf:playwright-kit-ops` — スクリプト実行 (upload_evidence 等のスクリプトはここに配置) +- `/ndf:google-auth` — Google API OAuth2 認証 +- `/ndf:google-drive` — Google Drive 汎用操作 +- `/ndf:playwright-scenario-test` — 全機能統括 diff --git a/plugins/ndf/skills/playwright-execution/SKILL.md b/plugins/ndf/skills/playwright-execution/SKILL.md index 0247137..0011abf 100644 --- a/plugins/ndf/skills/playwright-execution/SKILL.md +++ b/plugins/ndf/skills/playwright-execution/SKILL.md @@ -96,4 +96,6 @@ reports// - `/ndf:playwright-script-creation` — テストスクリプト作成 (実行の前段) - `/ndf:playwright-report` — Markdown レポート生成 - `/ndf:playwright-kit-ops` — スクリプト実行 (init_project / スキャン) +- `/ndf:playwright-browser-connect` — ブラウザ接続構成 (local / CDP remote) +- `/ndf:playwright-evidence-drive` — エビデンス Google Drive 保管 - `/ndf:playwright-scenario-test` — 全機能統括 diff --git a/plugins/ndf/skills/playwright-kit-ops/SKILL.md b/plugins/ndf/skills/playwright-kit-ops/SKILL.md index 76ed24c..b3ff459 100644 --- a/plugins/ndf/skills/playwright-kit-ops/SKILL.md +++ b/plugins/ndf/skills/playwright-kit-ops/SKILL.md @@ -104,5 +104,6 @@ playwright_kit Python パッケージ本体・templates・tests はこの skill - `/ndf:playwright-test-planning` — テスト計画 (方法論 + チェックリスト) - `/ndf:playwright-script-creation` — テストスクリプト作成 - `/ndf:playwright-execution` — テスト実行 + エビデンス収集 (video/trace/overlay/quality) +- `/ndf:playwright-browser-connect` — ブラウザ接続構成 (local / CDP remote) - `/ndf:playwright-report` — レポート生成 - `/ndf:playwright-scenario-test` — 全機能統括 diff --git a/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py b/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py index 95a21ca..9596ff2 100644 --- a/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py +++ b/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py @@ -49,6 +49,33 @@ def _expand_env(value: Any) -> Any: return value +# --- ブラウザ接続 --------------------------------------------------- + +BrowserMode = Literal["local", "cdp-remote"] +BROWSER_MODES: tuple[BrowserMode, ...] = ("local", "cdp-remote") + + +@dataclass +class BrowserConfig: + mode: BrowserMode = "local" + cdp_endpoint: str = "ws://localhost:9222" + + @classmethod + def from_raw(cls, raw: dict[str, Any]) -> "BrowserConfig": + base = cls() + mode_raw = str(raw.get("mode", base.mode)).lower() + if mode_raw not in BROWSER_MODES: + raise ValueError( + f"browser.mode は {BROWSER_MODES} のいずれかを指定してください " + f"(指定値: {mode_raw!r})" + ) + mode: BrowserMode = mode_raw # type: ignore[assignment] + return cls( + mode=mode, + cdp_endpoint=str(raw.get("cdp_endpoint", base.cdp_endpoint)), + ) + + # --- 接続/認証 ------------------------------------------------------- @dataclass @@ -260,6 +287,7 @@ class Config: runner: RunnerConfig report: ReportConfig config_path: Path # 設定ファイルの絶対パス(testcases_dir の解決基点) + browser: BrowserConfig = field(default_factory=BrowserConfig) # docs/checklists/checklist-common.md C8/C9 の境界曖昧さに対応する「除外」設定。 # console.error / pageerror の本文がいずれかの正規表現にマッチした場合は # 集計から除外し FAIL を抑制する。3rd party の既知 warning などを許容するための @@ -323,6 +351,7 @@ def _from_dict(cls, raw: dict[str, Any], *, config_path: Path) -> "Config": runner=RunnerConfig.from_raw(raw.get("runner") or {}), report=_report_from_raw(raw.get("report") or {}), config_path=config_path, + browser=BrowserConfig.from_raw(raw.get("browser") or {}), tolerated_console_errors=list(raw.get("tolerated_console_errors") or []), tolerated_page_errors=list(raw.get("tolerated_page_errors") or []), accessibility=_accessibility_from_raw(raw.get("accessibility") or {}), diff --git a/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template b/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template index f9de18e..efe5f26 100644 --- a/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template +++ b/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template @@ -11,6 +11,7 @@ fixture を追加する。 from __future__ import annotations import pytest +from playwright.sync_api import Browser, BrowserType # pytest-playwright の標準 fixture (browser_context_args / page) は plugin 経由で # 読み込まれる。playwright_kit 側 fixture (pwk_config / pwk_role_ / @@ -24,6 +25,26 @@ import pytest # return {**browser_type_launch_args, "headless": False, "slow_mo": 200} +# --- ブラウザ接続 fixture ------------------------------------------------ +# scenario.config.yaml の browser.mode に応じてブラウザ接続を切り替える。 +# - local: pytest-playwright デフォルト (chromium.launch()) +# - cdp-remote: connect_over_cdp() で既存 Chrome に CDP 接続 +# → /ndf:playwright-browser-connect 参照 + + +@pytest.fixture(scope="session") +def browser(browser_type: BrowserType, pwk_config) -> Browser: + browser_cfg = pwk_config.browser + if browser_cfg.mode == "cdp-remote": + b = browser_type.connect_over_cdp(browser_cfg.cdp_endpoint) + yield b + b.close() + else: + b = browser_type.launch(headless=pwk_config.playwright.headless) + yield b + b.close() + + # プロジェクト固有の fixture をここに追加する。例: # # @pytest.fixture diff --git a/plugins/ndf/skills/playwright-kit-ops/templates/scenario.config.yaml b/plugins/ndf/skills/playwright-kit-ops/templates/scenario.config.yaml index 0f749ab..95564d7 100644 --- a/plugins/ndf/skills/playwright-kit-ops/templates/scenario.config.yaml +++ b/plugins/ndf/skills/playwright-kit-ops/templates/scenario.config.yaml @@ -12,6 +12,19 @@ # .env ファイルや shell export で環境変数を設定して使用します。 # 例: export ADMIN_PASSWORD=secret または direnv / .env ファイルを活用 +# --- ブラウザ接続設定 -------------------------------------------------- +# local: playwright install chromium でインストールしたローカルブラウザ (デフォルト) +# cdp-remote: Chrome DevTools Protocol 経由でリモートブラウザに接続 +# → Windows / macOS のホスト Chrome を GUI 付きで操作可能 +# → ログイン済み Session (Google, AWS, Slack 等) をそのまま再利用 +# → 詳細は /ndf:playwright-browser-connect を参照 +browser: + mode: local + # cdp-remote 時のみ有効。環境変数で切り替え推奨: + # Windows (WSL2 Docker): export CDP_ENDPOINT=ws://host-gateway:9223 + # macOS (Docker Desktop): export CDP_ENDPOINT=ws://host.docker.internal:9222 + # cdp_endpoint: ${CDP_ENDPOINT:-ws://localhost:9222} + # --- 接続先 ---------------------------------------------------------- target: base_url: https://example.com diff --git a/plugins/ndf/skills/playwright-report/SKILL.md b/plugins/ndf/skills/playwright-report/SKILL.md index aca64e8..8da2568 100644 --- a/plugins/ndf/skills/playwright-report/SKILL.md +++ b/plugins/ndf/skills/playwright-report/SKILL.md @@ -42,8 +42,14 @@ report: phase_labels: {} ``` +## Google Drive での共有 + +レポート + エビデンスを Drive にアップロードしてチーム共有する場合は +`/ndf:playwright-evidence-drive` を参照。 + ## 関連 Skill - `/ndf:playwright-execution` — テスト実行 + エビデンス収集 -- `/ndf:playwright-kit-ops` — エビデンスアップロードツール (Drive 連携が必要な場合) +- `/ndf:playwright-evidence-drive` — エビデンス Google Drive 保管・共有 +- `/ndf:playwright-kit-ops` — エビデンスアップロードツール (スクリプト群) - `/ndf:playwright-scenario-test` — 全機能を統括したフルワークフロー diff --git a/plugins/ndf/skills/playwright-scenario-test/SKILL.md b/plugins/ndf/skills/playwright-scenario-test/SKILL.md index 3fefbe1..b38f595 100644 --- a/plugins/ndf/skills/playwright-scenario-test/SKILL.md +++ b/plugins/ndf/skills/playwright-scenario-test/SKILL.md @@ -29,6 +29,8 @@ Web アプリの E2E シナリオを **理論ベース** で計画し、**再現 | 3 | `/ndf:playwright-execution` | テスト実行 + エビデンス収集 (video/trace/overlay/quality) | | 4 | `/ndf:playwright-report` | レポート生成 (Markdown) | | -- | `/ndf:playwright-kit-ops` | ツール群 (init_project / スキャン / アップロード) | +| -- | `/ndf:playwright-browser-connect` | ブラウザ接続 (local / CDP remote) | +| -- | `/ndf:playwright-evidence-drive` | エビデンス Google Drive 保管・共有 | ## 標準ワークフロー From 6d0739267e10c5aa657926c814b950056b9964f4 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Tue, 26 May 2026 03:11:15 +0000 Subject: [PATCH 2/6] =?UTF-8?q?Fix:=20PR=20#19=20=E3=82=AF=E3=83=AD?= =?UTF-8?q?=E3=82=B9=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=20Round=202=20?= =?UTF-8?q?=E6=8C=87=E6=91=98=E5=AF=BE=E5=BF=9C=20(8=E4=BB=B6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SKILL.md: upload_evidence.py の引数 --parent → --parent-folder-id に修正 - SKILL.md: gdrive_upload_dir.py の引数を --local/--parent に修正 - SKILL.md: build_gdoc_with_drive_links.py の引数を --md/--folder/--run-id/--name に修正 - conftest.py.template: CDP 接続時に slow_mo を渡すよう修正 - conftest.py.template: local モードで pwk_config.playwright.headless を setdefault で尊重 - conftest.py.template: CDP モード既存 Session 再利用用の _cdp_default_context fixture 追加 - playwright-browser-connect/SKILL.md: conftest.py スニペットをテンプレートと同期 - scenario.config.yaml / SKILL.md: CDP URL を ws:// → http:// に統一 Co-Authored-By: Claude Opus 4.7 (1M context) --- .../playwright-browser-connect/SKILL.md | 53 +++++++++++++++---- .../skills/playwright-evidence-drive/SKILL.md | 24 +++++---- .../templates/conftest.py.template | 44 ++++++++++++--- .../templates/scenario.config.yaml | 6 +-- 4 files changed, 95 insertions(+), 32 deletions(-) diff --git a/plugins/ndf/skills/playwright-browser-connect/SKILL.md b/plugins/ndf/skills/playwright-browser-connect/SKILL.md index 8cbdd0e..371ce9a 100644 --- a/plugins/ndf/skills/playwright-browser-connect/SKILL.md +++ b/plugins/ndf/skills/playwright-browser-connect/SKILL.md @@ -28,7 +28,7 @@ browser: mode: local # cdp-remote 時のみ有効 - cdp_endpoint: ${CDP_ENDPOINT:-ws://localhost:9222} + cdp_endpoint: ${CDP_ENDPOINT:-http://localhost:9222} ``` ## パターン別セットアップ @@ -50,7 +50,7 @@ WSL2 上の Docker コンテナから Windows 側の Chrome GUI を CDP 経由 ``` Docker container (playwright) - ↓ ws://host-gateway:9223 + ↓ http://host-gateway:9223 WSL2 host ↓ portproxy or Node proxy Windows host @@ -125,13 +125,13 @@ services: ```yaml browser: mode: cdp-remote - cdp_endpoint: ${CDP_ENDPOINT:-ws://host-gateway:9223} + cdp_endpoint: ${CDP_ENDPOINT:-http://host-gateway:9223} ``` 環境変数で指定する場合: ```bash -export CDP_ENDPOINT="ws://host-gateway:9223" +export CDP_ENDPOINT="http://host-gateway:9223" ``` ### パターン 3: macOS ホスト Chrome (Docker → CDP) @@ -142,7 +142,7 @@ macOS 上の Docker コンテナから macOS 側の Chrome GUI を CDP 経由で ``` Docker container (playwright) - ↓ ws://host.docker.internal:9222 + ↓ http://host.docker.internal:9222 macOS host ↓ localhost:9222 Chrome (--remote-debugging-port=9222) @@ -173,7 +173,7 @@ macOS Docker Desktop は `host.docker.internal` を標準サポートしてい ```yaml browser: mode: cdp-remote - cdp_endpoint: ${CDP_ENDPOINT:-ws://host.docker.internal:9222} + cdp_endpoint: ${CDP_ENDPOINT:-http://host.docker.internal:9222} ``` ## conftest.py への統合 @@ -188,7 +188,11 @@ import pytest from playwright.sync_api import Browser, BrowserType @pytest.fixture(scope="session") -def browser(browser_type: BrowserType, pwk_config) -> Browser: +def browser( + browser_type: BrowserType, + browser_type_launch_args: dict, + pwk_config, +) -> Browser: """browser.mode に応じてブラウザ接続を切り替える。 - local: pytest-playwright デフォルト (chromium.launch()) @@ -196,17 +200,44 @@ def browser(browser_type: BrowserType, pwk_config) -> Browser: """ browser_cfg = pwk_config.browser if browser_cfg.mode == "cdp-remote": - browser = browser_type.connect_over_cdp(browser_cfg.cdp_endpoint) + if browser_type.name != "chromium": + pytest.fail( + f"cdp-remote モードは Chromium 専用です (現在: {browser_type.name})。" + "--browser chromium を指定するか、browser.mode を local に変更してください。" + ) + browser = browser_type.connect_over_cdp( + browser_cfg.cdp_endpoint, + slow_mo=browser_type_launch_args.get("slow_mo"), + ) yield browser browser.close() else: - # local mode: pytest-playwright デフォルトに委譲 - # (この fixture を定義しないのと同等) - browser = browser_type.launch() + launch_args = {**browser_type_launch_args} + launch_args.setdefault("headless", pwk_config.playwright.headless) + browser = browser_type.launch(**launch_args) yield browser browser.close() ``` +### CDP モードでの既存セッション再利用 + +CDP 接続先のブラウザが持つ既存コンテキスト (ログイン済み Session 等) を再利用するには、 +`browser.contexts[0]` を使用する。テンプレートの `conftest.py` には `_cdp_default_context` +fixture が用意されている。 + +```python +@pytest.fixture(scope="session") +def _cdp_default_context(browser, pwk_config): + """CDP モードで既存ブラウザの最初のコンテキストを返す。""" + if pwk_config.browser.mode == "cdp-remote" and browser.contexts: + return browser.contexts[0] + return None +``` + +`browser.new_context()` は新規コンテキストを作成するため、既存のログイン Session は引き継がれない。 +既存 Session を再利用したい場合は `_cdp_default_context` fixture を注入して +`context.new_page()` でページを取得すること。 + ## run.sh での利用 `cdp-remote` モード時は `playwright install chromium` が不要。 diff --git a/plugins/ndf/skills/playwright-evidence-drive/SKILL.md b/plugins/ndf/skills/playwright-evidence-drive/SKILL.md index 1917121..667fd14 100644 --- a/plugins/ndf/skills/playwright-evidence-drive/SKILL.md +++ b/plugins/ndf/skills/playwright-evidence-drive/SKILL.md @@ -55,19 +55,20 @@ allowed-tools: cd scenario-test uv run python scripts/upload_evidence.py reports//test_login/trace.zip \ --kind trace \ - --parent + --parent-folder-id ``` オプション: - `--kind {trace|har|video|any}` — ファイル種別 (拡張子から自動判定も可) -- `--parent ` — Drive 上のアップロード先フォルダ ID +- `--parent-folder-id ` — Drive 上のアップロード先フォルダ ID - `--public` — anyone/read 権限を付与 (trace viewer URL 生成に必要) ### ディレクトリ一括アップロード ```bash -uv run python scripts/gdrive_upload_dir.py reports// \ - --folder-id +uv run python scripts/gdrive_upload_dir.py \ + --local reports// \ + --parent ``` ディレクトリ構造を保ったまま Drive にミラーする。 @@ -89,12 +90,13 @@ Markdown を Google Docs 形式に変換してアップロード。 ```bash uv run python scripts/build_gdoc_with_drive_links.py \ - \ - reports// \ - --parent + --md reports//report.md \ + --folder \ + --run-id \ + --name "E2E テスト報告書 2026-05-26" ``` -1. Drive 上の `` フォルダからファイル一覧を取得 +1. Drive 上の `` 配下の `` フォルダからファイル一覧を取得 2. `report.md` 内の相対パスリンク (`./TC-XX/trace.zip`) を Drive URL に書き換え 3. 書き換え済み Markdown を Google Docs としてアップロード @@ -110,10 +112,10 @@ uv run python scripts/build_gdoc_with_drive_links.py \ reports//report.md で結果確認 ↓ [Drive 一括アップロード] - uv run python scripts/gdrive_upload_dir.py reports// --folder-id + uv run python scripts/gdrive_upload_dir.py --local reports// --parent ↓ [Docs 変換 + リンク埋め込み] - uv run python scripts/build_gdoc_with_drive_links.py reports// + uv run python scripts/build_gdoc_with_drive_links.py --md reports//report.md --folder --run-id --name "報告書" ↓ [共有] Docs URL をチーム (Slack / Google Chat) に共有 @@ -148,7 +150,7 @@ E2E テスト証跡/ ← 共有ドライブ or チ ```bash uv run python scripts/upload_evidence.py reports/.../trace.zip \ - --kind trace --public --parent + --kind trace --public --parent-folder-id ``` 出力例: diff --git a/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template b/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template index efe5f26..e2954fe 100644 --- a/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template +++ b/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template @@ -33,16 +33,46 @@ from playwright.sync_api import Browser, BrowserType @pytest.fixture(scope="session") -def browser(browser_type: BrowserType, pwk_config) -> Browser: +def browser( + browser_type: BrowserType, + browser_type_launch_args: dict, + pwk_config, +) -> Browser: browser_cfg = pwk_config.browser if browser_cfg.mode == "cdp-remote": - b = browser_type.connect_over_cdp(browser_cfg.cdp_endpoint) - yield b - b.close() + if browser_type.name != "chromium": + pytest.fail( + f"cdp-remote モードは Chromium 専用です (現在: {browser_type.name})。" + "--browser chromium を指定するか、browser.mode を local に変更してください。" + ) + browser = browser_type.connect_over_cdp( + browser_cfg.cdp_endpoint, + slow_mo=browser_type_launch_args.get("slow_mo"), + ) + yield browser + browser.close() else: - b = browser_type.launch(headless=pwk_config.playwright.headless) - yield b - b.close() + launch_args = {**browser_type_launch_args} + launch_args.setdefault("headless", pwk_config.playwright.headless) + browser = browser_type.launch(**launch_args) + yield browser + browser.close() + + +@pytest.fixture(scope="session") +def _cdp_default_context(browser, pwk_config): + """CDP モードで既存ブラウザの最初のコンテキスト (ログイン済み Session) を返す。 + + CDP 接続先の Chrome が持つ既存 context (browser.contexts[0]) を再利用する。 + local モードでは None を返す。 + + 使い方: + テスト側で既存セッションを使いたい場合は _cdp_default_context を注入し、 + context.new_page() でページを取得する。 + """ + if pwk_config.browser.mode == "cdp-remote" and browser.contexts: + return browser.contexts[0] + return None # プロジェクト固有の fixture をここに追加する。例: diff --git a/plugins/ndf/skills/playwright-kit-ops/templates/scenario.config.yaml b/plugins/ndf/skills/playwright-kit-ops/templates/scenario.config.yaml index 95564d7..f92bd10 100644 --- a/plugins/ndf/skills/playwright-kit-ops/templates/scenario.config.yaml +++ b/plugins/ndf/skills/playwright-kit-ops/templates/scenario.config.yaml @@ -21,9 +21,9 @@ browser: mode: local # cdp-remote 時のみ有効。環境変数で切り替え推奨: - # Windows (WSL2 Docker): export CDP_ENDPOINT=ws://host-gateway:9223 - # macOS (Docker Desktop): export CDP_ENDPOINT=ws://host.docker.internal:9222 - # cdp_endpoint: ${CDP_ENDPOINT:-ws://localhost:9222} + # Windows (WSL2 Docker): export CDP_ENDPOINT=http://host-gateway:9223 + # macOS (Docker Desktop): export CDP_ENDPOINT=http://host.docker.internal:9222 + # cdp_endpoint: ${CDP_ENDPOINT:-http://localhost:9222} # --- 接続先 ---------------------------------------------------------- target: From 0e4a82f7c605e23f79481f76048307bb09541b2b Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Tue, 26 May 2026 03:26:17 +0000 Subject: [PATCH 3/6] =?UTF-8?q?Fix:=20PR=20#19=20=E3=82=AF=E3=83=AD?= =?UTF-8?q?=E3=82=B9=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=20Round=203=20?= =?UTF-8?q?=E6=8C=87=E6=91=98=E5=AF=BE=E5=BF=9C=20(4=E4=BB=B6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SKILL.md: TCP proxy を廃止し --remote-allow-origins=* フラグによる Host ヘッダ検証回避に差し替え (proxy 不要でシンプル化) - conftest.py.template: CDP接続/localモード両方で scenario.config.yaml の playwright.slow_mo_ms をフォールバックとして反映 - config.py: cdp_endpoint が null (YAML でキーのみ定義) の場合に "None" 文字列にならないよう or 演算子でガード Co-Authored-By: Claude Opus 4.7 (1M context) --- plugins/ndf/CHANGELOG.md | 26 +++++++ .../playwright-browser-connect/SKILL.md | 73 ++++++++++--------- .../playwright_kit/config.py | 4 +- .../templates/conftest.py.template | 8 +- 4 files changed, 74 insertions(+), 37 deletions(-) diff --git a/plugins/ndf/CHANGELOG.md b/plugins/ndf/CHANGELOG.md index 200ba47..ac70103 100644 --- a/plugins/ndf/CHANGELOG.md +++ b/plugins/ndf/CHANGELOG.md @@ -1,5 +1,31 @@ # NDF Plugin CHANGELOG +### v4.10.0 (playwright-browser-connect / playwright-evidence-drive Skill 追加) + +`/ndf:playwright-browser-connect` と `/ndf:playwright-evidence-drive` を新規 Skill +として追加。CDP リモートブラウザ接続と Google Drive エビデンスアーカイブを +playwright-scenario-test エコシステムから独立した専門 Skill に分離。 + +- **新規 Skill `playwright-browser-connect`**: + - `scenario.config.yaml` の `browser.mode: cdp-remote` で既存 Chrome に + CDP (Chrome DevTools Protocol) 接続するワークフローを提供 + - `conftest.py.template` に browser fixture を追加 (mode 切り替え) + - `config.py` に `BrowserConfig` dataclass を追加 +- **新規 Skill `playwright-evidence-drive`**: + - テスト実行後のエビデンス (video/trace/screenshot/HAR) を Google Drive に + 自動アーカイブする手順を提供 + - 認証は `ndf:google-auth` に委譲 +- **conftest.py.template の改善** (PR #19 クロスレビュー対応): + - `browser_type_launch_args` を browser fixture の依存に追加し、 + `--headed` / `slow_mo` / `channel` 等が local モードで反映されるよう修正 + - CDP 接続時に Chromium 以外のブラウザが選択された場合の fail-fast チェックを追加 + - 変数名 `b` → `browser` に改名 (可読性向上) +- **config.py の修正** (PR #19 クロスレビュー対応): + - `BrowserConfig.cdp_endpoint` の既定値を `ws://localhost:9222` → + `http://localhost:9222` に変更 (Playwright の `connect_over_cdp()` は + HTTP endpoint から `/json/version` 経由で WebSocket URL を自動解決する) +- Skills: 44個 → **46個** + ### v4.7.6 (fix/review-pr-comments: PRコメント取得を3ソース対応に拡張) PRレビューコメント取得が review body / PR レベルコメントを含む3ソースに対応。 diff --git a/plugins/ndf/skills/playwright-browser-connect/SKILL.md b/plugins/ndf/skills/playwright-browser-connect/SKILL.md index 371ce9a..9619efc 100644 --- a/plugins/ndf/skills/playwright-browser-connect/SKILL.md +++ b/plugins/ndf/skills/playwright-browser-connect/SKILL.md @@ -50,12 +50,12 @@ WSL2 上の Docker コンテナから Windows 側の Chrome GUI を CDP 経由 ``` Docker container (playwright) - ↓ http://host-gateway:9223 + ↓ http://host-gateway:9222 WSL2 host - ↓ portproxy or Node proxy + ↓ NAT bridge Windows host ↓ localhost:9222 -Chrome (--remote-debugging-port=9222) +Chrome (--remote-debugging-port=9222 --remote-allow-origins=*) ``` #### セットアップ手順 @@ -66,6 +66,7 @@ Chrome (--remote-debugging-port=9222) # Windows PowerShell & "C:\Program Files\Google\Chrome\Application\chrome.exe" ` --remote-debugging-port=9222 ` + --remote-allow-origins=* ` --user-data-dir="C:\tmp\chrome-debug" ``` @@ -74,34 +75,29 @@ Chrome (--remote-debugging-port=9222) ```powershell # 全 Chrome プロセスを閉じてから & "C:\Program Files\Google\Chrome\Application\chrome.exe" ` - --remote-debugging-port=9222 + --remote-debugging-port=9222 ` + --remote-allow-origins=* ``` -**Step 2: Node.js Proxy (9223 → 9222) を設置** - -Chrome CDP の WebSocket は `Host` ヘッダ検証があるため、直接ポートフォワードでは接続できない。 -Node.js proxy で `Host` を書き換える。 - -```javascript -// proxy.js (Windows 側に配置) -const net = require("net"); -const server = net.createServer((client) => { - const chrome = net.connect(9222, "127.0.0.1", () => { - client.pipe(chrome); - chrome.pipe(client); - }); - chrome.on("error", () => client.destroy()); - client.on("error", () => chrome.destroy()); -}); -server.listen(9223, "0.0.0.0", () => { - console.log("CDP proxy listening on 0.0.0.0:9223 → 127.0.0.1:9222"); -}); -``` +**Step 2: `--remote-allow-origins=*` で Host ヘッダ検証を無効化** + +Chrome CDP の WebSocket は Host ヘッダ検証があるため、リモートからの接続がデフォルトで拒否される。 +Chrome 起動時に `--remote-allow-origins=*` フラグを付けることで、任意の Origin からの接続を許可できる。 + +Step 1 のコマンドにフラグを追加: ```powershell -node proxy.js +# Windows PowerShell +& "C:\Program Files\Google\Chrome\Application\chrome.exe" ` + --remote-debugging-port=9222 ` + --remote-allow-origins=* ` + --user-data-dir="C:\tmp\chrome-debug" ``` +これにより proxy を設置する必要がなくなり、Docker コンテナから直接 CDP エンドポイントに接続できる。 + +> **Note**: `--remote-allow-origins=*` は Chrome 106+ で利用可能。セキュリティ上、信頼できるネットワーク内での利用に限定すること。 + **Step 3: WSL2 .wslconfig (NAT mode 確認)** ```ini @@ -125,13 +121,13 @@ services: ```yaml browser: mode: cdp-remote - cdp_endpoint: ${CDP_ENDPOINT:-http://host-gateway:9223} + cdp_endpoint: ${CDP_ENDPOINT:-http://host-gateway:9222} ``` 環境変数で指定する場合: ```bash -export CDP_ENDPOINT="http://host-gateway:9223" +export CDP_ENDPOINT="http://host-gateway:9222" ``` ### パターン 3: macOS ホスト Chrome (Docker → CDP) @@ -145,7 +141,7 @@ Docker container (playwright) ↓ http://host.docker.internal:9222 macOS host ↓ localhost:9222 -Chrome (--remote-debugging-port=9222) +Chrome (--remote-debugging-port=9222 --remote-allow-origins=*) ``` #### セットアップ手順 @@ -155,6 +151,7 @@ Chrome (--remote-debugging-port=9222) ```bash /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \ --remote-debugging-port=9222 \ + --remote-allow-origins=* \ --user-data-dir="$HOME/tmp/chrome-debug" ``` @@ -163,12 +160,14 @@ Chrome (--remote-debugging-port=9222) ```bash # 全 Chrome プロセスを終了してから /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \ - --remote-debugging-port=9222 + --remote-debugging-port=9222 \ + --remote-allow-origins=* ``` **Step 2: scenario.config.yaml** -macOS Docker Desktop は `host.docker.internal` を標準サポートしているため proxy 不要。 +macOS Docker Desktop は `host.docker.internal` を標準サポートしており、 +`--remote-allow-origins=*` で Host ヘッダ検証を無効化しているため proxy 不要。 ```yaml browser: @@ -199,6 +198,10 @@ def browser( - cdp-remote: chromium.connect_over_cdp(endpoint) """ browser_cfg = pwk_config.browser + # slow_mo: browser_type_launch_args が優先、なければ config の slow_mo_ms + _slow_mo = browser_type_launch_args.get( + "slow_mo", pwk_config.playwright.slow_mo_ms or None + ) if browser_cfg.mode == "cdp-remote": if browser_type.name != "chromium": pytest.fail( @@ -207,13 +210,15 @@ def browser( ) browser = browser_type.connect_over_cdp( browser_cfg.cdp_endpoint, - slow_mo=browser_type_launch_args.get("slow_mo"), + slow_mo=_slow_mo, ) yield browser browser.close() else: launch_args = {**browser_type_launch_args} launch_args.setdefault("headless", pwk_config.playwright.headless) + if _slow_mo is not None: + launch_args.setdefault("slow_mo", _slow_mo) browser = browser_type.launch(**launch_args) yield browser browser.close() @@ -248,7 +253,7 @@ CDP 接続テストを手動確認する場合: ```bash # エンドポイントの疎通確認 -curl -s http://host-gateway:9223/json/version | python3 -m json.tool +curl -s http://host-gateway:9222/json/version | python3 -m json.tool ``` ## トラブルシュート @@ -258,7 +263,7 @@ curl -s http://host-gateway:9223/json/version | python3 -m json.tool | 症状 | 原因 | 対策 | |---|---|---| | `connect_over_cdp` で接続拒否 | Chrome が起動していない / ポートが違う | `curl http:///json/version` で確認 | -| WebSocket handshake 失敗 | Host ヘッダ不一致 | Node proxy 経由に変更 | +| WebSocket handshake 失敗 | Host ヘッダ不一致 | Chrome 起動時に `--remote-allow-origins=*` を付与 | | ページ操作が異常に遅い | VPN / DNS 解決の遅延 | `extra_hosts` で IP 直指定 | ### Windows (WSL2) 固有 @@ -267,7 +272,7 @@ curl -s http://host-gateway:9223/json/version | python3 -m json.tool |---|---|---| | `host-gateway` 解決不能 | Docker Compose の `extra_hosts` 未設定 | `extra_hosts: ["host-gateway:host-gateway"]` を追加 | | IPv6 でバインドされる | WSL2 が IPv6 優先 | proxy.js で `0.0.0.0` を明示 | -| `netsh portproxy` で接続ループ | portproxy の自己参照 | Node proxy に切り替え | +| `netsh portproxy` で接続ループ | portproxy の自己参照 | `--remote-allow-origins=*` を使い proxy を廃止 | | mirrored mode で動かない | mirrored は localhost 共有だが CDP の WS 接続でポート競合 | NAT mode に戻す | ### macOS 固有 diff --git a/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py b/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py index 9596ff2..d8e8209 100644 --- a/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py +++ b/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py @@ -58,7 +58,7 @@ def _expand_env(value: Any) -> Any: @dataclass class BrowserConfig: mode: BrowserMode = "local" - cdp_endpoint: str = "ws://localhost:9222" + cdp_endpoint: str = "http://localhost:9222" @classmethod def from_raw(cls, raw: dict[str, Any]) -> "BrowserConfig": @@ -72,7 +72,7 @@ def from_raw(cls, raw: dict[str, Any]) -> "BrowserConfig": mode: BrowserMode = mode_raw # type: ignore[assignment] return cls( mode=mode, - cdp_endpoint=str(raw.get("cdp_endpoint", base.cdp_endpoint)), + cdp_endpoint=str(raw.get("cdp_endpoint") or base.cdp_endpoint), ) diff --git a/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template b/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template index e2954fe..630ecfc 100644 --- a/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template +++ b/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template @@ -39,6 +39,10 @@ def browser( pwk_config, ) -> Browser: browser_cfg = pwk_config.browser + # slow_mo: browser_type_launch_args が優先、なければ config の slow_mo_ms + _slow_mo = browser_type_launch_args.get( + "slow_mo", pwk_config.playwright.slow_mo_ms or None + ) if browser_cfg.mode == "cdp-remote": if browser_type.name != "chromium": pytest.fail( @@ -47,13 +51,15 @@ def browser( ) browser = browser_type.connect_over_cdp( browser_cfg.cdp_endpoint, - slow_mo=browser_type_launch_args.get("slow_mo"), + slow_mo=_slow_mo, ) yield browser browser.close() else: launch_args = {**browser_type_launch_args} launch_args.setdefault("headless", pwk_config.playwright.headless) + if _slow_mo is not None: + launch_args.setdefault("slow_mo", _slow_mo) browser = browser_type.launch(**launch_args) yield browser browser.close() From b5aa008a5d3141bf457f77c7652a6e87fd03842c Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Tue, 26 May 2026 03:37:50 +0000 Subject: [PATCH 4/6] =?UTF-8?q?Fix:=20PR=20#19=20=E3=82=AF=E3=83=AD?= =?UTF-8?q?=E3=82=B9=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=20Round=204=20?= =?UTF-8?q?=E6=8C=87=E6=91=98=203=E4=BB=B6=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SKILL.md: Chrome の 127.0.0.1 バインド問題に対応するネットワーク別接続ガイドを追加 (--remote-debugging-address=0.0.0.0 / socat / netsh portproxy の3方式 + 早見表) - config.py: browser.mode が null の場合に ValueError でクラッシュする問題を修正 (raw.get("mode") or base.mode でデフォルト値へフォールバック) - marketplace.json: NDF の description を v4.10.0 / 46 skills に更新 Co-Authored-By: Claude Opus 4.7 (1M context) --- .claude-plugin/marketplace.json | 2 +- .../playwright-browser-connect/SKILL.md | 67 +++++++++++++++++++ .../playwright_kit/config.py | 2 +- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 4ebcfc4..10db5a5 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -8,7 +8,7 @@ { "name": "ndf", "source": "./plugins/ndf", - "description": "All-in-one plugin (v4.0.0): 8 specialized agents, 33 skills (PR/review workflows, principles, data analysis, Codex CLI integration, skill usage stats), SessionStart hook (transcript retention >= 90 days), Stop hook (AI-summarized Slack notifications). Codex CLI is invoked via /ndf:codex skill or corder agent (MCP server removed in v4.0.0)." + "description": "All-in-one plugin (v4.10.0): 8 specialized agents (model-tiered), 46 skills including pytest-playwright E2E testing (7 focused skills: test-planning, script-creation, execution, report, kit-ops, browser-connect, evidence-drive), CDP remote browser support, Google Drive evidence archival, PR/review workflows, principles, data analysis, Codex/Gemini CLI integration, skill usage stats. SessionStart hook (transcript retention >= 90 days), Stop hook (AI-summarized Slack notifications)." }, { "name": "affaan-m", diff --git a/plugins/ndf/skills/playwright-browser-connect/SKILL.md b/plugins/ndf/skills/playwright-browser-connect/SKILL.md index 9619efc..134d623 100644 --- a/plugins/ndf/skills/playwright-browser-connect/SKILL.md +++ b/plugins/ndf/skills/playwright-browser-connect/SKILL.md @@ -98,6 +98,8 @@ Step 1 のコマンドにフラグを追加: > **Note**: `--remote-allow-origins=*` は Chrome 106+ で利用可能。セキュリティ上、信頼できるネットワーク内での利用に限定すること。 +> **Important**: Chrome はデフォルトで `127.0.0.1` にバインドするため、`--remote-allow-origins=*` だけでは WSL2/Docker から接続できない場合がある。対処方法は「ネットワーク別接続ガイド」セクションを参照。 + **Step 3: WSL2 .wslconfig (NAT mode 確認)** ```ini @@ -256,6 +258,71 @@ CDP 接続テストを手動確認する場合: curl -s http://host-gateway:9222/json/version | python3 -m json.tool ``` +## ネットワーク別接続ガイド + +Chrome はデフォルトで `127.0.0.1` (ループバック) にバインドするため、同一ホストからしか CDP エンドポイントにアクセスできない。Docker コンテナや WSL2 からリモート接続する場合は、以下のいずれかの方法でネットワーク到達性を確保する必要がある。 + +### 方法 1: `--remote-debugging-address=0.0.0.0` (推奨) + +Chrome 起動時に全インターフェースでリッスンさせる。最もシンプルな方法。 + +```bash +# Linux / macOS +google-chrome \ + --remote-debugging-port=9222 \ + --remote-debugging-address=0.0.0.0 \ + --remote-allow-origins=* +``` + +```powershell +# Windows PowerShell +& "C:\Program Files\Google\Chrome\Application\chrome.exe" ` + --remote-debugging-port=9222 ` + --remote-debugging-address=0.0.0.0 ` + --remote-allow-origins=* +``` + +> **Security**: `0.0.0.0` はすべてのネットワークインターフェースに公開するため、信頼できるネットワーク内でのみ使用すること。ファイアウォールでポート 9222 へのアクセスを制限することを推奨。 + +### 方法 2: socat によるポートフォワード (Linux) + +Chrome を `127.0.0.1` バインドのまま維持し、socat でリモートからのアクセスを中継する。 + +```bash +# Chrome は通常どおり起動 (127.0.0.1 バインド) +google-chrome --remote-debugging-port=9222 --remote-allow-origins=* + +# 別ターミナルで socat を起動 +socat TCP-LISTEN:9222,bind=0.0.0.0,reuseaddr,fork TCP:127.0.0.1:9222 +``` + +### 方法 3: netsh portproxy (Windows → WSL2) + +Windows ホストの Chrome を WSL2 からアクセスする場合、Windows 側でポートフォワードを設定する。 + +```powershell +# 管理者権限の PowerShell で実行 +netsh interface portproxy add v4tov4 ` + listenaddress=0.0.0.0 listenport=9222 ` + connectaddress=127.0.0.1 connectport=9222 + +# 確認 +netsh interface portproxy show all + +# 削除する場合 +netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=9222 +``` + +### 接続先の早見表 + +| 実行環境 | Chrome の場所 | 推奨方法 | CDP エンドポイント | +|---|---|---|---| +| ローカル (同一ホスト) | 同一ホスト | 設定不要 | `http://localhost:9222` | +| Docker → ホスト (macOS) | macOS ホスト | 方法 1 | `http://host.docker.internal:9222` | +| Docker → ホスト (Linux) | Linux ホスト | 方法 1 or 2 | `http://host.docker.internal:9222` or `http://172.17.0.1:9222` | +| Docker (WSL2) → Windows | Windows ホスト | 方法 1 or 3 | `http://host-gateway:9222` | +| WSL2 → Windows | Windows ホスト | 方法 1 or 3 | `http://$(cat /etc/resolv.conf \| grep nameserver \| awk '{print $2}'):9222` | + ## トラブルシュート ### 共通 diff --git a/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py b/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py index d8e8209..0f3e0a7 100644 --- a/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py +++ b/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py @@ -63,7 +63,7 @@ class BrowserConfig: @classmethod def from_raw(cls, raw: dict[str, Any]) -> "BrowserConfig": base = cls() - mode_raw = str(raw.get("mode", base.mode)).lower() + mode_raw = str(raw.get("mode") or base.mode).lower() if mode_raw not in BROWSER_MODES: raise ValueError( f"browser.mode は {BROWSER_MODES} のいずれかを指定してください " From 72e4fdf2b254bd0d5607a057c9b5ff2ae5319d16 Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Tue, 26 May 2026 03:48:50 +0000 Subject: [PATCH 5/6] =?UTF-8?q?Fix:=20scenario.config.yaml=20=E3=81=AE=20W?= =?UTF-8?q?SL2=20=E4=BE=8B=E7=A4=BA=E3=83=9D=E3=83=BC=E3=83=88=E3=82=92=20?= =?UTF-8?q?9222=20=E3=81=AB=E7=B5=B1=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SKILL.md や他の例示と一致するよう、旧 proxy 前提の 9223 を標準の 9222 に修正。 Co-Authored-By: Claude Opus 4.7 (1M context) --- .../skills/playwright-kit-ops/templates/scenario.config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ndf/skills/playwright-kit-ops/templates/scenario.config.yaml b/plugins/ndf/skills/playwright-kit-ops/templates/scenario.config.yaml index f92bd10..6bd08b4 100644 --- a/plugins/ndf/skills/playwright-kit-ops/templates/scenario.config.yaml +++ b/plugins/ndf/skills/playwright-kit-ops/templates/scenario.config.yaml @@ -21,7 +21,7 @@ browser: mode: local # cdp-remote 時のみ有効。環境変数で切り替え推奨: - # Windows (WSL2 Docker): export CDP_ENDPOINT=http://host-gateway:9223 + # Windows (WSL2 Docker): export CDP_ENDPOINT=http://host-gateway:9222 # macOS (Docker Desktop): export CDP_ENDPOINT=http://host.docker.internal:9222 # cdp_endpoint: ${CDP_ENDPOINT:-http://localhost:9222} From 4e8101e5153ed443b98932e239a648b86c0113ef Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Tue, 26 May 2026 04:02:08 +0000 Subject: [PATCH 6/6] =?UTF-8?q?Fix:=20PR=20#20=20=E3=82=AF=E3=83=AD?= =?UTF-8?q?=E3=82=B9=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=20Round=206=20?= =?UTF-8?q?=E6=8C=87=E6=91=98=E5=AF=BE=E5=BF=9C=20(4=E4=BB=B6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. [major] conftest.py.template: context/page fixture を cdp-remote 時に 既存コンテキスト/ページを返すようオーバーライド。標準テストコードが CDP のログイン済み Session を自動的に使えるようになった。 2. [major] SKILL.md: Docker (WSL2) の接続先を host-gateway → host.docker.internal に修正。WSL2 直接実行時の Windows ホスト IP 取得方法も注記追加。 3. [minor] conftest.py.template: CDP での browser.close() が disconnect であり リモートブラウザ自体は終了しない旨のコメントを追加。 4. [minor] config.py: cdp_endpoint が空文字列/空白の場合にデフォルト値へ フォールバックするバリデーションを追加し、docstring で挙動を明記。 Co-Authored-By: Claude Opus 4.7 (1M context) --- .../playwright-browser-connect/SKILL.md | 69 +++++++++++-------- .../playwright_kit/config.py | 13 +++- .../templates/conftest.py.template | 36 ++++++++-- 3 files changed, 85 insertions(+), 33 deletions(-) diff --git a/plugins/ndf/skills/playwright-browser-connect/SKILL.md b/plugins/ndf/skills/playwright-browser-connect/SKILL.md index 134d623..e3d8685 100644 --- a/plugins/ndf/skills/playwright-browser-connect/SKILL.md +++ b/plugins/ndf/skills/playwright-browser-connect/SKILL.md @@ -50,9 +50,9 @@ WSL2 上の Docker コンテナから Windows 側の Chrome GUI を CDP 経由 ``` Docker container (playwright) - ↓ http://host-gateway:9222 -WSL2 host - ↓ NAT bridge + ↓ http://host.docker.internal:9222 +Docker Desktop (WSL2 backend) + ↓ host.docker.internal → Windows host IP Windows host ↓ localhost:9222 Chrome (--remote-debugging-port=9222 --remote-allow-origins=*) @@ -108,30 +108,28 @@ Step 1 のコマンドにフラグを追加: networkingMode=NAT ``` -**Step 4: Docker Compose で host-gateway を設定** +**Step 4: scenario.config.yaml** -```yaml -# docker-compose.yml -services: - app: - extra_hosts: - - "host-gateway:host-gateway" -``` - -**Step 5: scenario.config.yaml** +Docker Desktop (WSL2 backend) は `host.docker.internal` を標準サポートしている。 ```yaml browser: mode: cdp-remote - cdp_endpoint: ${CDP_ENDPOINT:-http://host-gateway:9222} + cdp_endpoint: ${CDP_ENDPOINT:-http://host.docker.internal:9222} ``` 環境変数で指定する場合: ```bash -export CDP_ENDPOINT="http://host-gateway:9222" +export CDP_ENDPOINT="http://host.docker.internal:9222" ``` +> **Note (Docker Desktop を使わず WSL2 から直接実行する場合)**: `host.docker.internal` は Docker Desktop 固有の DNS 名のため利用できない。代わりに Windows ホストの IP アドレスを直接指定する: +> ```bash +> # WSL2 から Windows ホスト IP を取得 +> export CDP_ENDPOINT="http://$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):9222" +> ``` + ### パターン 3: macOS ホスト Chrome (Docker → CDP) macOS 上の Docker コンテナから macOS 側の Chrome GUI を CDP 経由で操作する。 @@ -215,6 +213,8 @@ def browser( slow_mo=_slow_mo, ) yield browser + # CDP 接続の場合、close() は接続を切断 (disconnect) するだけで、 + # リモートブラウザ自体は終了しない。 browser.close() else: launch_args = {**browser_type_launch_args} @@ -228,22 +228,35 @@ def browser( ### CDP モードでの既存セッション再利用 -CDP 接続先のブラウザが持つ既存コンテキスト (ログイン済み Session 等) を再利用するには、 -`browser.contexts[0]` を使用する。テンプレートの `conftest.py` には `_cdp_default_context` -fixture が用意されている。 +`cdp-remote` モードでは、テンプレートの `conftest.py` が `context` / `page` fixture を +自動的にオーバーライドし、CDP 接続先の既存コンテキスト (ログイン済み Session) を返す。 +標準のテストコードは何も変更せずに既存セッションを利用できる。 ```python @pytest.fixture(scope="session") -def _cdp_default_context(browser, pwk_config): - """CDP モードで既存ブラウザの最初のコンテキストを返す。""" - if pwk_config.browser.mode == "cdp-remote" and browser.contexts: - return browser.contexts[0] - return None +def context(browser, pwk_config, _cdp_default_context): + """cdp-remote: 既存コンテキスト / local: 新規コンテキスト""" + if pwk_config.browser.mode == "cdp-remote" and _cdp_default_context is not None: + yield _cdp_default_context + else: + ctx = browser.new_context() + yield ctx + ctx.close() + +@pytest.fixture(scope="session") +def page(context, pwk_config): + """cdp-remote: 既存ページ / local: 新規ページ""" + if pwk_config.browser.mode == "cdp-remote" and context.pages: + yield context.pages[0] + else: + pg = context.new_page() + yield pg + pg.close() ``` `browser.new_context()` は新規コンテキストを作成するため、既存のログイン Session は引き継がれない。 -既存 Session を再利用したい場合は `_cdp_default_context` fixture を注入して -`context.new_page()` でページを取得すること。 +`cdp-remote` モードでは `context` fixture が自動的に `browser.contexts[0]` を返すため、 +テスト側で特別な対応は不要。 ## run.sh での利用 @@ -255,7 +268,7 @@ CDP 接続テストを手動確認する場合: ```bash # エンドポイントの疎通確認 -curl -s http://host-gateway:9222/json/version | python3 -m json.tool +curl -s http://host.docker.internal:9222/json/version | python3 -m json.tool ``` ## ネットワーク別接続ガイド @@ -320,7 +333,7 @@ netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=9222 | ローカル (同一ホスト) | 同一ホスト | 設定不要 | `http://localhost:9222` | | Docker → ホスト (macOS) | macOS ホスト | 方法 1 | `http://host.docker.internal:9222` | | Docker → ホスト (Linux) | Linux ホスト | 方法 1 or 2 | `http://host.docker.internal:9222` or `http://172.17.0.1:9222` | -| Docker (WSL2) → Windows | Windows ホスト | 方法 1 or 3 | `http://host-gateway:9222` | +| Docker (WSL2) → Windows | Windows ホスト | 方法 1 or 3 | `http://host.docker.internal:9222` | | WSL2 → Windows | Windows ホスト | 方法 1 or 3 | `http://$(cat /etc/resolv.conf \| grep nameserver \| awk '{print $2}'):9222` | ## トラブルシュート @@ -337,7 +350,7 @@ netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=9222 | 症状 | 原因 | 対策 | |---|---|---| -| `host-gateway` 解決不能 | Docker Compose の `extra_hosts` 未設定 | `extra_hosts: ["host-gateway:host-gateway"]` を追加 | +| `host.docker.internal` 解決不能 | Docker Desktop 未使用 or 古いバージョン | Docker Desktop を使用するか、WSL2 直接の場合は Windows ホスト IP を直接指定 | | IPv6 でバインドされる | WSL2 が IPv6 優先 | proxy.js で `0.0.0.0` を明示 | | `netsh portproxy` で接続ループ | portproxy の自己参照 | `--remote-allow-origins=*` を使い proxy を廃止 | | mirrored mode で動かない | mirrored は localhost 共有だが CDP の WS 接続でポート競合 | NAT mode に戻す | diff --git a/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py b/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py index 0f3e0a7..18436b4 100644 --- a/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py +++ b/plugins/ndf/skills/playwright-kit-ops/playwright_kit/config.py @@ -57,6 +57,12 @@ def _expand_env(value: Any) -> Any: @dataclass class BrowserConfig: + """ブラウザ接続設定。 + + cdp_endpoint が空文字列や空白のみの場合はデフォルト値 + ``http://localhost:9222`` にフォールバックする。 + """ + mode: BrowserMode = "local" cdp_endpoint: str = "http://localhost:9222" @@ -70,9 +76,14 @@ def from_raw(cls, raw: dict[str, Any]) -> "BrowserConfig": f"(指定値: {mode_raw!r})" ) mode: BrowserMode = mode_raw # type: ignore[assignment] + # cdp_endpoint: 空文字列・空白のみの場合はデフォルト値にフォールバック + cdp_raw = raw.get("cdp_endpoint") + cdp_endpoint = str(cdp_raw).strip() if cdp_raw else "" + if not cdp_endpoint: + cdp_endpoint = base.cdp_endpoint return cls( mode=mode, - cdp_endpoint=str(raw.get("cdp_endpoint") or base.cdp_endpoint), + cdp_endpoint=cdp_endpoint, ) diff --git a/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template b/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template index 630ecfc..9ad04d4 100644 --- a/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template +++ b/plugins/ndf/skills/playwright-kit-ops/templates/conftest.py.template @@ -54,6 +54,8 @@ def browser( slow_mo=_slow_mo, ) yield browser + # CDP 接続の場合、close() は接続を切断 (disconnect) するだけで、 + # リモートブラウザ自体は終了しない。次回のテスト実行でも同じ Chrome を再利用できる。 browser.close() else: launch_args = {**browser_type_launch_args} @@ -71,16 +73,42 @@ def _cdp_default_context(browser, pwk_config): CDP 接続先の Chrome が持つ既存 context (browser.contexts[0]) を再利用する。 local モードでは None を返す。 - - 使い方: - テスト側で既存セッションを使いたい場合は _cdp_default_context を注入し、 - context.new_page() でページを取得する。 """ if pwk_config.browser.mode == "cdp-remote" and browser.contexts: return browser.contexts[0] return None +@pytest.fixture(scope="session") +def context(browser, pwk_config, _cdp_default_context): + """pytest-playwright の context fixture をオーバーライド。 + + cdp-remote モードでは既存コンテキスト (ログイン済み Session) を返し、 + local モードでは新規コンテキストを作成する (pytest-playwright 既定動作)。 + """ + if pwk_config.browser.mode == "cdp-remote" and _cdp_default_context is not None: + yield _cdp_default_context + else: + ctx = browser.new_context() + yield ctx + ctx.close() + + +@pytest.fixture(scope="session") +def page(context, pwk_config): + """pytest-playwright の page fixture をオーバーライド。 + + cdp-remote モードでは既存コンテキストの最初のページを返し (なければ新規作成)、 + local モードでは新規ページを作成する (pytest-playwright 既定動作)。 + """ + if pwk_config.browser.mode == "cdp-remote" and context.pages: + yield context.pages[0] + else: + pg = context.new_page() + yield pg + pg.close() + + # プロジェクト固有の fixture をここに追加する。例: # # @pytest.fixture