ホーム / 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 スクリプトでローカル Web アプリをテストするための指針です。

進め方

  1. アプリが静的か動的かを判断します。
  2. 動的ページがアイドル状態になるのを待ってから、描画済み DOM を調べます。
  3. 可視セレクタ、スクリーンショット、ブラウザログで UI の自動化と診断を行います。

向いている用途

スモークテスト、UI 回帰の調査、セレクタ探索、スクリーンショット、コンソールログの取得。

補足とリスク

Python の例とサーバー管理ヘルパーを含みます。ローカル URL へのアクセス、ブラウザ自動化、スクリーンショットやログの書き込み、ローカル開発サーバーとして渡された shell コマンドの起動を行えます。認証情報は含まれません。実行前にコマンドとパスを確認してください。