首頁 / Skills / 開發提效 / 網頁應用測試 Web Application Testing
開發提效

網頁應用測試 Web Application Testing

Anthropic, PBCApache-2.0Skill 語言: 英文
授權已核對含腳本
演示真實執行紀錄 · 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

  1. It registers the console and pageerror listeners before goto, so messages logged during the initial render are captured.
  2. It waits for networkidle so the dynamic page has finished rendering before it inspects anything.
  3. It lists every visible button, using get_by_role("button") plus an is_visible() filter.
  4. It clicks the button named "Save profile", waits for the network to settle again, and prints the captured console messages.
  5. It saves a full-page screenshot to smoke_test.png. This happens in finally, 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 with role="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> without role="button", the lookup will time out. In that case, switch to page.get_by_text("Save profile") or add a data-testid and use get_by_test_id.
  • Exact match: exact=True is 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: networkidle can 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 指令碼測試本機網頁應用。

運作方式

  1. 判斷應用程式是靜態頁面或動態應用。
  2. 在檢查渲染後的 DOM 前,等待動態頁面進入閒置狀態。
  3. 使用可見選擇器、螢幕截圖和瀏覽器日誌來自動化並診斷介面行為。

適合情境

冒煙測試、介面回歸排查、選擇器探索、截圖與主控台日誌擷取。

說明與風險

包含 Python 範例與伺服器生命週期輔助程式。它可存取本機 URL、啟動瀏覽器自動化、寫入截圖或日誌,並啟動作為本機開發伺服器提供的 shell 指令。不含憑證;執行前請檢閱指令與檔案路徑。