Test d'applications Web
Manuel de compétences d'agent pour les tests d'applications Web basées sur Playwright avec des aides à l'orchestration de serveur et des conseils de dépannage.
Source: Contenu adapté de anthropics/skills (MIT).
Pour tester des applications Web locales, écrivez des scripts Python Playwright natifs.
Scripts d'aide disponibles:
scripts/with_server.py- Gère le cycle de vie du serveur (prend en charge plusieurs serveurs)
Exécutez toujours les scripts avec--helpen premier pour voir l'utilisation. NE lisez PAS la source avant d'avoir d'abord essayé d'exécuter le script et constaté qu'une solution personnalisée est absolument nécessaire. Ces scripts peuvent être très volumineux et ainsi polluer votre fenêtre contextuelle. Ils existent pour être appelés directement sous forme de scripts boîte noire plutôt que d'être ingérés dans votre fenêtre contextuelle.
Arbre de décision: choisir votre approche
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 selectorsExemple: utilisation de with_server.py
Pour démarrer un serveur, exécutez d'abord--help, puis utilisez l'assistant:
Serveur unique:
python scripts/with_server.py --server "npm run dev" --port 5173 -- python your_automation.pyPlusieurs serveurs (par exemple, 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.pyPour créer un script d'automatisation, incluez uniquement la logique Playwright (les serveurs sont gérés automatiquement):
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()Modèle de reconnaissance puis d'action
-
Inspecter le DOM rendu:
page.screenshot(path='/tmp/inspect.png', full_page=True) content = page.content() page.locator('button').all() -
Identifier les sélecteurs à partir des résultats de l'inspection
-
Exécuter des actions à l'aide des sélecteurs découverts
Piège courant
N'inspectez pas le DOM avant d'attendrenetworkidlesur les applications dynamiques
Attendezpage.wait_for_load_state('networkidle')avant l'inspection
Meilleures pratiques
- Utilisez les scripts fournis comme boîtes noires - Pour accomplir une tâche, déterminez si l'un des scripts disponibles dans
scripts/peut vous aider. Ces scripts gèrent de manière fiable les flux de travail courants et complexes sans encombrer la fenêtre contextuelle. Utilisez--helppour voir l’utilisation, puis invoquez directement. - Utilisez
sync_playwright()pour les scripts synchrones - Fermez toujours le navigateur lorsque vous avez terminé
- Utilisez des sélecteurs descriptifs:
text=,role=, des sélecteurs CSS ou des ID. - Ajoutez les attentes appropriées:
page.wait_for_selector()oupage.wait_for_timeout()
Fichiers de référence
- exemples/ - Exemples illustrant des modèles courants:
element_discovery.py– Découverte de boutons, de liens et d'entrées sur une pagestatic_html_automation.py- Utilisation des URL file:// pour le HTML localconsole_logging.py- Capture des journaux de console pendant l'automatisation
Fichiers de ressources
LICENCE.txt
Ressource binaire
exemples/console_logging.py
Télécharger examples/console_logging.py
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")exemples/element_discovery.py
Télécharger exemples/element_discovery.py
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()exemples/static_html_automation.py
Télécharger exemples/static_html_automation.py
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
Télécharger scripts/with_server.py
#!/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()Voir dans GitHub
Constructeur Mcp
Manuel de compétences des agents pour créer des serveurs Model Context Protocol, définir des outils et rédiger des suites d'évaluation sur lesquelles Claude Skills peut s'appuyer.
Co-rédaction de documents
Guidez les utilisateurs à travers un flux de travail structuré pour la co-création de documentation. À utiliser lorsque l'utilisateur souhaite rédiger de la documentation, des propositions, des spécifications techniques, des documents de décision ou un contenu structuré similaire. Ce flux de travail aide les utilisateurs à transférer efficacement le contexte, à affiner le contenu par itération et à vérifier que le document fonctionne pour les lecteurs. Déclenchez lorsque l'utilisateur mentionne la rédaction de documents, la création de propositions, la rédaction de spécifications ou des tâches de documentation similaires.
claudeskills Docs