playwright-verify
Cài + dùng Playwright bằng standalone .mjs script (không qua npx playwright test / *.spec.ts) để verify code nhanh, một lần: chụp ảnh localhost/file://, đọc console/pageerror, đo getBoundingClientRect khi phần tử không thấy/không bấm được, auth bypass qua addCookies+addInitScript; việc NHIỀU BƯỚC thì mode phiên bền connectOverCDP (tab/cookie giữ nguyên giữa các lượt, không viết mù cả kịch bản). Dùng khi user nói 'verify bằng playwright', 'chụp ảnh trang', 'test nhanh UI bằng script', 'verify nhiều bước', 'giữ session giữa các lần chạy', 'claude-in-chrome bị chặn localhost', 'không click được / không thấy phần tử', hoặc invoke /playwright-verify. KHÁC uat-nonit-testcase (bộ test case UAT cho non-IT) và claude-in-chrome (extension, bị chặn localhost/file://) — đây là hướng dẫn CHUNG áp dụng mọi task.
How do I install this agent skill?
npx skills add https://github.com/rheinmir/setup --skill playwright-verifyIs this agent skill safe to install?
- Gen Agent Trust Hubpass
This skill facilitates UI verification and testing using Playwright. It involves downloading browser binaries from Playwright's official CDN, executing shell commands for environment setup, and generating standalone JavaScript scripts to be executed via Node.js. It also includes instructions for managing persistent browser sessions via the Remote Debugging Protocol.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
Skill: playwright-verify
Đúc kết từ GH#96 — công cụ verify RẺ (< 5s/lần, không LLM) và là cách DUY NHẤT tương tác
được với localhost/file:// khi claude-in-chrome bị chặn 2 scheme này trên máy.
WHAT
Purpose và context
- Purpose: verify code nhanh, một lần, bằng Playwright chạy qua standalone
.mjs+node(không test runner): chụp ảnhlocalhost/file://, moi lỗi console/pageerror/http/requestfailed, đo phần tử thật, auth bypass; việc nhiều bước thì phiên bềnconnectOverCDP. - Trigger (when to use):
claude-in-chromebáoFrame with ID 0 is showing error pagehoặcCan't interact with browser-internal or unparseable URLstrênlocalhost:*/file://.- Cần chẩn đoán phần tử UI "không thấy" / "không bấm được" — ảnh chụp không đủ, cần số đo
thật (
getBoundingClientRect,getComputedStyle). - Cần verify 1 giả thuyết code rồi vứt (không xứng tạo
*.spec.ts+ test runner). - Cần test qua dev-login/session giả thay vì đăng nhập SSO thật mỗi lần.
- User nói 'verify bằng playwright', 'chụp ảnh trang', 'test nhanh UI bằng script', 'verify nhiều bước', 'giữ session giữa các lần chạy', 'không click được / không thấy phần tử', hoặc
/playwright-verify.
- User nói 'verify bằng playwright', 'chụp ảnh trang', 'test nhanh UI bằng script', 'verify nhiều bước', 'giữ session giữa các lần chạy', 'không click được / không thấy phần tử', hoặc
- Non-goals: không tạo
*.spec.ts+ test runner (npx playwright test), không phải bộ test case UAT (→ uat-nonit-testcase), không thay claude-in-chrome cho trang web ngoài bình thường, không commit script vào repo đích.
Mental model
giả thuyết cần verify → (đã cài?) → script .mjs một-phát: launch → gắn 4 kênh lỗi → goto (load + wait) → screenshot/đo → close → đọc log + ảnh → vứt. Nhánh nhiều bước: một Chrome CDP riêng (profile tạm) ← mỗi lượt step-N.mjs bám vào, state sống giữa các lượt → pkill khi xong.
Input và output contract
| Field | Required? | Ý nghĩa | |
|---|---|---|---|
| In | URL (localhost:* / file:// / khác) | có | trang cần verify |
| In | project có @playwright/test trong node_modules | có | script phải chạy TỪ thư mục đó (hoặc NODE_PATH) |
| In | cookie/localStorage dev-login | không | cho auth bypass |
| Out | ảnh chụp (vd /tmp/check.png) + log [console]/[pageerror]/[http]/[reqfail] | có | bằng chứng; ảnh sạch một mình KHÔNG đủ |
| Out | số đo getBoundingClientRect/getComputedStyle | khi chẩn đoán phần tử | số thật thay vì đoán từ ảnh |
| Out | "xong" | — | giả thuyết xác nhận/bác bỏ bằng log + ảnh; script đã dọn; Chrome CDP (nếu có) đã pkill |
Rules và capabilities
- RULE-01 (MUST):
import { chromium } from "@playwright/test"phải chạy TỪ TRONG thư mục project có@playwright/testtrongnode_modules— ESM resolve theocwd, không theo vị trí file script. Script ở thư mục khác (vd/tmp) →cpvào project trước khi chạy, hoặc trỏNODE_PATH. - RULE-02 (MUST):
waitUntil: "networkidle"TREO VÔ THỜI HẠN trên Next.js dev server — HMR/webpack dev giữ 1 kết nối long-poll/websocket sống liên tục nên network không bao giờ "idle". DùngwaitUntil: "load"+page.waitForTimeout(N)cố định. - RULE-03 (MUST): Auth bypass cho dev-login:
context.addCookies([{url, name, value}])(ưu tiênurlthay vìdomain+pathriêng lẻ — tránh cookie không match) +context.addInitScript(...)setlocalStorage— set state TRƯỚC khi gọinewPage(), không phải sau. - RULE-04 (MUST): 1
contextcho mỗi route độc lập nếu app có logic "gặp 401 ở API phụ → tự xoá session toàn cục" — dùng lại 1 context cho nhiều navigation khiến lỗi route N hỏng lây route N+1. - RULE-05 (MUST): Chẩn đoán "không thấy/không bấm được": đừng chỉ nhìn ảnh chụp — gọi
page.evaluate(() => el.getBoundingClientRect())+getComputedStyle(el)lấy số đo thật;locator.click()tự báo lỗi rõ ("element is not visible") kèm log các bước thử lại, đọc log đó trước khi đoán nguyên nhân. - RULE-06 (MUST): Ảnh chụp sạch không chứng minh gì — luôn moi 4 kênh lỗi, không chỉ 2:
console(typeerror) ·pageerror·responsecóstatus() >= 400·requestfailed. Analytics crash, API 5xx, promise rejection không hiện lên pixel nào. Gắn vàopageTRƯỚCgoto: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): Mode phiên bền: một Chrome riêng, một profile riêng (
--user-data-dirtạm). Không bao giờ--remote-debugging-portlên Chrome cá nhân của user — macOS bật hộp thoại xin phép và script sẽ giẫm lên tab user đang làm. - RULE-08 (MUST): File script standalone không vào git — chạy từ scratchpad, không commit vào repo đích.
- RULE-09 (MUST): Touch only what the task requires — no opportunistic changes.
- Capabilities: chạy trình duyệt headless cục bộ + đọc/ghi file tạm; mạng ngoài chỉ khi cài binary (CDN), có timeout.
Failure boundaries
npx playwright installbị chặn mạng/treo → blocked, báo lỗi rõ (có timeout), không để lệnh treo vô hạn.- ESM không resolve
@playwright/test(chạy sai cwd) → cp script vào project hoặcNODE_PATH, rồi chạy lại. networkidletreo trên Next.js dev → đổi sangload+waitForTimeout(không phải lỗi app).- Phần tử không thấy/không bấm → đo số thật + đọc log
locator.click()trước khi kết luận; không đoán từ ảnh.
HOW
Main workflow
| Step | Type | Inputs | Action | Outputs/exit | Failure/next |
|---|---|---|---|---|---|
| W01 | deterministic | máy | Kiểm đã cài (ls ~/Library/Caches/ms-playwright); chưa có thì cài | binary sẵn | CDN bị chặn → blocked |
| W02 | judgment | giả thuyết + URL | Viết 1 file .mjs chạy thẳng bằng node, gắn 4 kênh lỗi trước goto | script | — |
| W03 | effect | script | Chạy từ đúng thư mục (node check.mjs), đọc log + ảnh; dọn script | log + ảnh | resolve lỗi → cp/NODE_PATH, lặp W03 |
| W04 | effect | việc nhiều bước | Mode phiên bền connectOverCDP (B01) | state giữ giữa lượt | xong → pkill |
Chi tiết từng bước (nguồn chân lý cho W01–W04):
- Kiểm tra đã cài chưa trước khi cài lại:
ls ~/Library/Caches/ms-playwright(macOS) — binary cache dùng chung mọi project, không cần cài lại per-repo.- Chưa có:
pnpm add -D @playwright/test(bỏ qua nếu project đã có sẵn trongdevDependencies) rồinpx playwright install chromium. npx playwright installtải binary từ CDN ngoài (cdn.playwright.dev) — sandbox/CI có allowlist mạng sẽ treo hoặc fail. Set timeout khi gọi tự động; nếu bị chặn, báo lỗi rõ thay vì để lệnh treo vô thời hạn.
- Chưa có:
- Viết 1 file
.mjschạy thẳng bằngnode(không quanpx playwright test) — nặng hơn cho việc verify-rồi-vứt: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(); - Chạy từ đúng thư mục (xem Rules #1),
node check.mjs, đọc console/pageerror log + ảnh chụp. Dọn file.mjssau khi xong nếu chạy trong 1 project cụ thể (không cần xoá gì khỏi git — script không nằm trong repo nếu chạy từ scratch dir). - Việc NHIỀU BƯỚC có điều kiện → mode phiên bền (học từ browser-use/browser-harness,
09/2026). Script một-phát bắt agent viết mù cả kịch bản; sai một bước là chạy lại từ
đăng nhập. Thay vào đó: dựng MỘT Chrome có cổng CDP, mỗi lượt là một script nhỏ bám vào —
tab, cookie,
localStorage, scroll giữ nguyên giữa các lượt, agent nhìn rồi mới quyết bước kế.# 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 &
Xong việc:// 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ạypkill -f "remote-debugging-port=9333". Đo 09/09/2026 (python-playwright, cùng trangfile://): launch mới 1.1–1.9s/lượt, mất state;connectOverCDP0.65–0.80s/lượt,window.__markersống qua tiến trình mới (3/3). Bản.mjstrên chưa chạy bằng node trong phiên đo — API đồng nhất với bản python đã chạy.
Branches
| ID | Kind | Guard | Hành vi | Skip / failure | Rejoin |
|---|---|---|---|---|---|
| B01 | conditional_required | việc NHIỀU BƯỚC có điều kiện (cần nhìn rồi mới quyết bước kế) | một Chrome riêng --remote-debugging-port=9333 + profile tạm; mỗi lượt step-N.mjs connectOverCDP | việc một-phát → skip; không bao giờ bám Chrome cá nhân | kết thúc bằng pkill -f "remote-debugging-port=9333" |
| B02 | user_optional | trang cần dev-login/session giả | context.addCookies + context.addInitScript TRƯỚC newPage(); 1 context/route nếu app tự xoá session khi 401 | — | W03 |
| B03 | recovery | phần tử "không thấy/không bấm được" | page.evaluate(() => el.getBoundingClientRect()) + getComputedStyle(el), đọc log retry của locator.click() | — | W03 |
Validation và stopping
Kết luận dựa trên 4 kênh lỗi + ảnh + số đo, không chỉ ảnh. Mỗi lượt chạy < 5s, không LLM. Dừng khi giả thuyết đã có bằng chứng; dọn script + pkill Chrome CDP.
Examples
- Positive: claude-in-chrome báo
Frame with ID 0 is showing error pagetrênhttp://localhost:3000/some-page→ cpcheck.mjsvào project →node check.mjs→/tmp/check.png+ log sạch cả[console]/[pageerror]/[http]/[reqfail]→ xác nhận trang render, xoá script. - Boundary/failure: script dùng
waitUntil: "networkidle"trên Next.js dev → treo vô hạn; sửa thànhwaitUntil: "load"+page.waitForTimeout(1500)→ chạy xong. Ảnh sạch nhưng log có[http] 500 /api/x→ KHÔNG báo pass.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/rheinmir/setup/playwright-verify">View playwright-verify on skillZs</a>