演示真实运行记录 · claude-sonnet-5-5 · 2026年10月
I have a local React application already running at http://localhost:5173. Create a Python Playwright smoke-test script that first waits for the dynamic page to become idle, then discovers the visible buttons, clicks the button named "Save profile", captures browser console messages, and saves a full-page screenshot. Explain any assumptions about selectors. Use the webapp-testing skill.
Skill: webapp-testing
I couldn't save the script to disk because the Write tool is disabled in this session. The full script is below, so you can save it as smoke_test.py yourself. I haven't run it.
import sys
from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeout
URL = "http://localhost:5173"
BUTTON_NAME = "Save profile"
SCREENSHOT_PATH = "smoke_test.png"
console_messages = []
def main() -> int:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
# Register listeners before navigation so early messages are captured
page.on("console", lambda msg: console_messages.append((msg.type, msg.text)))
page.on("pageerror", lambda err: console_messages.append(("pageerror", str(err))))
exit_code = 0
try:
page.goto(URL)
# Critical for dynamic apps: wait for JS to render and network to settle
page.wait_for_load_state("networkidle")
# Discover visible buttons
buttons = [b for b in page.get_by_role("button").all() if b.is_visible()]
print(f"Found {len(buttons)} visible button(s):")
for i, b in enumerate(buttons):
label = (b.inner_text() or b.get_attribute("aria-label") or "").strip()
print(f" [{i}] {label!r}")
# Click by accessible name
target = page.get_by_role("button", name=BUTTON_NAME, exact=True)
target.wait_for(state="visible", timeout=5000)
target.click()
page.wait_for_load_state("networkidle")
print(f"Clicked button {BUTTON_NAME!r}")
except PlaywrightTimeout as e:
print(f"FAIL: button {BUTTON_NAME!r} not found/visible: {e}")
exit_code = 1
finally:
page.screenshot(path=SCREENSHOT_PATH, full_page=True)
print(f"Screenshot saved to {SCREENSHOT_PATH}")
print(f"\nConsole messages ({len(console_messages)}):")
for kind, text in console_messages:
print(f" [{kind}] {text}")
if any(k in ("error", "pageerror") for k, _ in console_messages):
print("WARNING: console errors detected")
exit_code = exit_code or 1
browser.close()
return exit_code
if __name__ == "__main__":
sys.exit(main())
Run it with python smoke_test.py. Your server is already up, so you don't need with_server.py. If you haven't installed Playwright yet, run pip install playwright && playwright install chromium first.
What it does, in order
- It registers the
consoleandpageerrorlisteners beforegoto, so messages logged during the initial render are captured. - It waits for
networkidleso the dynamic page has finished rendering before it inspects anything. - It lists every visible button, using
get_by_role("button")plus anis_visible()filter. - It clicks the button named "Save profile", waits for the network to settle again, and prints the captured console messages.
- It saves a full-page screenshot to
smoke_test.png. This happens infinally, so you get a screenshot even if the click fails.
Assumptions about selectors
- Role and name: I used
get_by_role("button", name="Save profile", exact=True). This assumes the control is a real<button>,<input type="submit">, or an element withrole="button". Its accessible name must be exactly "Save profile", whether from its text,aria-label, or an associated label. It also keeps working if CSS classes change. - A
<div onClick>won't match: If "Save profile" is a styled<div>withoutrole="button", the lookup will time out. In that case, switch topage.get_by_text("Save profile")or add adata-testidand useget_by_test_id. - Exact match:
exact=Trueis a case-sensitive, full-string match. Remove it if the label might change, for example to "Save profile…" or "Saving…". - One match only: Playwright's strict mode raises an error if more than one button matches. If the page has duplicates, such as one per tab, scope the lookup, for example
page.locator("form").get_by_role(...). - Idle waiting:
networkidlecan hang if the app polls, uses websockets, or runs HMR traffic. If that happens, wait for a specific element instead of network idle. - Failure condition: The script exits non-zero if the button isn't found or if any console error or uncaught page error appears.
Real run recorded with claude-code / claude-sonnet-5-5. Output is shown verbatim, unmodified.
它做什么
指导代理使用原生 Python Playwright 脚本测试本地网页应用。
工作方式
- 判断应用是静态页面还是动态应用。
- 在检查渲染后的 DOM 前,等待动态页面进入空闲状态。
- 使用可见选择器、截图和浏览器日志来自动化并诊断界面行为。
适合场景
冒烟测试、界面回归排查、选择器发现、截图与控制台日志采集。
说明与风险
包含 Python 示例和服务器生命周期辅助脚本。它可以访问本地 URL、启动浏览器自动化、写入截图或日志,并启动作为本地开发服务器提供的 shell 命令。不包含凭据;运行前请审查命令和文件路径。