Start / Skills / Entwickler-Produktivität / Web Application Testing
Entwickler-Produktivität

Web Application Testing

Anthropic, PBCApache-2.0Sprache des Skills: Englisch
Lizenz geprüftEnthält Skripte
DemoEchter Lauf · claude-sonnet-5-5 · Oktober 2026
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.

Zweck

Leitet Agenten beim Testen lokaler Webanwendungen mit nativen Python-Playwright-Skripten an.

Arbeitsweise

  1. Erkennt, ob die Anwendung statisch oder dynamisch ist.
  2. Wartet bei dynamischen Seiten auf den Ruhezustand, bevor das gerenderte DOM geprüft wird.
  3. Nutzt sichtbare Selektoren, Screenshots und Browser-Protokolle zur UI-Automatisierung und Diagnose.

Geeignet für

Smoke-Tests, Untersuchung von UI-Regressionen, Selektor-Ermittlung, Screenshots und Konsolenprotokolle.

Hinweise & Risiken

Enthält Python-Beispiele und einen Helfer für den Serverlebenszyklus. Es kann lokale URLs öffnen, Browserautomatisierung starten, Screenshots oder Protokolle schreiben und als lokale Entwicklungsserver angegebene Shell-Befehle starten. Es enthält keine Zugangsdaten; prüfen Sie Befehle und Pfade vor der Ausführung.