Webapp-Tests
Handbuch zu Agentenfähigkeiten für Playwright-basierte Web-App-Tests mit Server-Orchestrierungshilfen und Tipps zur Fehlerbehebung.
Quelle: Inhalt angepasst von Anthropics/Skills (MIT).
Um lokale Webanwendungen zu testen, schreiben Sie native Python-Playwright-Skripte.
Hilfsskripte verfügbar:
scripts/with_server.py– Verwaltet den Serverlebenszyklus (unterstützt mehrere Server)
Führen Sie Skripte immer zuerst mit--helpaus, um die Nutzung zu sehen. Lesen Sie die Quelle NICHT, bis Sie versuchen, das Skript auszuführen und feststellen, dass eine angepasste Lösung unbedingt erforderlich ist. Diese Skripte können sehr groß sein und somit Ihr Kontextfenster verschmutzen. Sie dienen dazu, direkt als Black-Box-Skripte aufgerufen zu werden, anstatt sie in Ihr Kontextfenster aufzunehmen.
Entscheidungsbaum: Wählen Sie Ihren Ansatz
User task -> Is it static HTML?
Yes -> Read HTML file directly to identify selectors
Success -> Write Playwright script using selectors
Fails/Incomplete -> Treat as dynamic (below)
No (dynamic webapp) -> Is the server already running?
No -> Run: python scripts/with_server.py --help
Then use the helper + write simplified Playwright script
Yes -> Reconnaissance-then-action:
1. Navigate and wait for networkidle
2. Take screenshot or inspect DOM
3. Identify selectors from rendered state
4. Execute actions with discovered selectorsBeispiel: Verwendung von with_server.py
Um einen Server zu starten, führen Sie zuerst--helpaus und verwenden Sie dann den Helfer:
Einzelserver:
python scripts/with_server.py --server "npm run dev" --port 5173 -- python your_automation.pyMehrere Server (z. B. Backend + Frontend):
python scripts/with_server.py \
--server "cd backend && python server.py" --port 3000 \
--server "cd frontend && npm run dev" --port 5173 \
-- python your_automation.pyUm ein Automatisierungsskript zu erstellen, beziehen Sie nur Playwright-Logik ein (Server werden automatisch verwaltet):
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True) # Always launch chromium in headless mode
page = browser.new_page()
page.goto('http://localhost:5173') # Server already running and ready
page.wait_for_load_state('networkidle') # CRITICAL: Wait for JS to execute
# ... your automation logic
browser.close()Aufklärung-dann-Aktion-Muster
-
Überprüfen Sie das gerenderte DOM:
page.screenshot(path='/tmp/inspect.png', full_page=True) content = page.content() page.locator('button').all() -
Identifizieren Sie Selektoren anhand der Inspektionsergebnisse
-
Aktionen ausführen mit erkannten Selektoren
Häufiger Fallstrick
Inspizieren Sie das DOM nicht, bevor Sie bei dynamischen Apps aufnetworkidlewarten
Warten Sie vor der Inspektion aufpage.wait_for_load_state('networkidle')
Best Practices
- Gebündelte Skripte als Blackboxen verwenden – Um eine Aufgabe zu erfüllen, überlegen Sie, ob eines der in
scripts/verfügbaren Skripte hilfreich sein kann. Diese Skripte bewältigen gängige, komplexe Arbeitsabläufe zuverlässig, ohne das Kontextfenster zu überladen. Verwenden Sie--help, um die Nutzung anzuzeigen, und rufen Sie sie dann direkt auf. - Verwenden Sie
sync_playwright()für synchrone Skripte - Schließen Sie immer den Browser, wenn Sie fertig sind
- Verwenden Sie beschreibende Selektoren:
text=,role=, CSS-Selektoren oder IDs - Fügen Sie entsprechende Wartezeiten hinzu:
page.wait_for_selector()oderpage.wait_for_timeout()
Referenzdateien
- Beispiele/ – Beispiele, die häufige Muster zeigen:
element_discovery.py– Erkennen von Schaltflächen, Links und Eingaben auf einer Seitestatic_html_automation.py– Verwendung von file://-URLs für lokales HTMLconsole_logging.py– Erfassen von Konsolenprotokollen während der Automatisierung
Ressourcendateien
LIZENZ.txt
Binäre Ressource
example/console_logging.py
Beispiele/console_logging.py herunterladen
from playwright.sync_api import sync_playwright
# Example: Capturing console logs during browser automation
url = 'http://localhost:5173' # Replace with your URL
console_logs = []
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={'width': 1920, 'height': 1080})
# Set up console log capture
def handle_console_message(msg):
console_logs.append(f"[{msg.type}] {msg.text}")
print(f"Console: [{msg.type}] {msg.text}")
page.on("console", handle_console_message)
# Navigate to page
page.goto(url)
page.wait_for_load_state('networkidle')
# Interact with the page (triggers console logs)
page.click('text=Dashboard')
page.wait_for_timeout(1000)
browser.close()
# Save console logs to file
with open('/mnt/user-data/outputs/console.log', 'w') as f:
f.write('\n'.join(console_logs))
print(f"\nCaptured {len(console_logs)} console messages")
print(f"Logs saved to: /mnt/user-data/outputs/console.log")Beispiele/element_discovery.py
Beispiele/element_discovery.py herunterladen
from playwright.sync_api import sync_playwright
# Example: Discovering buttons and other elements on a page
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
# Navigate to page and wait for it to fully load
page.goto('http://localhost:5173')
page.wait_for_load_state('networkidle')
# Discover all buttons on the page
buttons = page.locator('button').all()
print(f"Found {len(buttons)} buttons:")
for i, button in enumerate(buttons):
text = button.inner_text() if button.is_visible() else "[hidden]"
print(f" [{i}] {text}")
# Discover links
links = page.locator('a[href]').all()
print(f"\nFound {len(links)} links:")
for link in links[:5]: # Show first 5
text = link.inner_text().strip()
href = link.get_attribute('href')
print(f" - {text} -> {href}")
# Discover input fields
inputs = page.locator('input, textarea, select').all()
print(f"\nFound {len(inputs)} input fields:")
for input_elem in inputs:
name = input_elem.get_attribute('name') or input_elem.get_attribute('id') or "[unnamed]"
input_type = input_elem.get_attribute('type') or 'text'
print(f" - {name} ({input_type})")
# Take screenshot for visual reference
page.screenshot(path='/tmp/page_discovery.png', full_page=True)
print("\nScreenshot saved to /tmp/page_discovery.png")
browser.close()Beispiele/static_html_automation.py
Beispiele/static_html_automation.py herunterladen
from playwright.sync_api import sync_playwright
import os
# Example: Automating interaction with static HTML files using file:// URLs
html_file_path = os.path.abspath('path/to/your/file.html')
file_url = f'file://{html_file_path}'
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={'width': 1920, 'height': 1080})
# Navigate to local HTML file
page.goto(file_url)
# Take screenshot
page.screenshot(path='/mnt/user-data/outputs/static_page.png', full_page=True)
# Interact with elements
page.click('text=Click Me')
page.fill('#name', 'John Doe')
page.fill('#email', '[email protected]')
# Submit form
page.click('button[type="submit"]')
page.wait_for_timeout(500)
# Take final screenshot
page.screenshot(path='/mnt/user-data/outputs/after_submit.png', full_page=True)
browser.close()
print("Static HTML automation completed!")scripts/with_server.py
Scripts/with_server.py herunterladen
#!/usr/bin/env python3
"""
Start one or more servers, wait for them to be ready, run a command, then clean up.
Usage:
# Single server
python scripts/with_server.py --server "npm run dev" --port 5173 -- python automation.py
python scripts/with_server.py --server "npm start" --port 3000 -- python test.py
# Multiple servers
python scripts/with_server.py \
--server "cd backend && python server.py" --port 3000 \
--server "cd frontend && npm run dev" --port 5173 \
-- python test.py
"""
import subprocess
import socket
import time
import sys
import argparse
def is_server_ready(port, timeout=30):
"""Wait for server to be ready by polling the port."""
start_time = time.time()
while time.time() - start_time < timeout:
try:
with socket.create_connection(('localhost', port), timeout=1):
return True
except (socket.error, ConnectionRefusedError):
time.sleep(0.5)
return False
def main():
parser = argparse.ArgumentParser(description='Run command with one or more servers')
parser.add_argument('--server', action='append', dest='servers', required=True, help='Server command (can be repeated)')
parser.add_argument('--port', action='append', dest='ports', type=int, required=True, help='Port for each server (must match --server count)')
parser.add_argument('--timeout', type=int, default=30, help='Timeout in seconds per server (default: 30)')
parser.add_argument('command', nargs=argparse.REMAINDER, help='Command to run after server(s) ready')
args = parser.parse_args()
# Remove the '--' separator if present
if args.command and args.command[0] == '--':
args.command = args.command[1:]
if not args.command:
print("Error: No command specified to run")
sys.exit(1)
# Parse server configurations
if len(args.servers) != len(args.ports):
print("Error: Number of --server and --port arguments must match")
sys.exit(1)
servers = []
for cmd, port in zip(args.servers, args.ports):
servers.append({'cmd': cmd, 'port': port})
server_processes = []
try:
# Start all servers
for i, server in enumerate(servers):
print(f"Starting server {i+1}/{len(servers)}: {server['cmd']}")
# Use shell=True to support commands with cd and &&
process = subprocess.Popen(
server['cmd'],
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
server_processes.append(process)
# Wait for this server to be ready
print(f"Waiting for server on port {server['port']}...")
if not is_server_ready(server['port'], timeout=args.timeout):
raise RuntimeError(f"Server failed to start on port {server['port']} within {args.timeout}s")
print(f"Server ready on port {server['port']}")
print(f"\nAll {len(servers)} server(s) ready")
# Run the command
print(f"Running: {' '.join(args.command)}\n")
result = subprocess.run(args.command)
sys.exit(result.returncode)
finally:
# Clean up all servers
print(f"\nStopping {len(server_processes)} server(s)...")
for i, process in enumerate(server_processes):
try:
process.terminate()
process.wait(timeout=5)
except subprocess.TimeoutExpired:
process.kill()
process.wait()
print(f"Server {i+1} stopped")
print("All servers stopped")
if __name__ == '__main__':
main()Siehe in GitHub
Mcp Builder
Claude Skills kann sich auf das Agenten-Skill-Handbuch zum Erstellen von Model Context Protocol-Servern, zum Definieren von Tools und zum Schreiben von Evaluierungs-Suites verlassen.
Mitverfassen von Dokumenten
Führen Sie Benutzer durch einen strukturierten Workflow für die gemeinsame Erstellung von Dokumentationen. Verwenden Sie diese Option, wenn der Benutzer Dokumentationen, Vorschläge, technische Spezifikationen, Entscheidungsdokumente oder ähnliche strukturierte Inhalte schreiben möchte. Dieser Workflow hilft Benutzern, Kontext effizient zu übertragen, Inhalte durch Iteration zu verfeinern und zu überprüfen, ob das Dokument für Leser funktioniert. Wird ausgelöst, wenn der Benutzer das Schreiben von Dokumenten, das Erstellen von Vorschlägen, das Entwerfen von Spezifikationen oder ähnliche Dokumentationsaufgaben erwähnt.
claudeskills Docs