Files
rpa_vision_v3/scripts/test_palette_cross_machine_navigateur_10jan2026.py
Dom a27b74cf22 v1.0 - Version stable: multi-PC, détection UI-DETR-1, 3 modes exécution
- Frontend v4 accessible sur réseau local (192.168.1.40)
- Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard)
- Ollama GPU fonctionnel
- Self-healing interactif
- Dashboard confiance

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 11:23:51 +01:00

480 lines
17 KiB
Python

#!/usr/bin/env python3
"""
Test Palette Cross-Machine dans Navigateur - 10 janvier 2026
Auteur : Dom, Alice, Kiro
Ce script teste le fonctionnement réel de la palette d'outils VWB
dans le navigateur avec détection automatique d'URL cross-machine.
"""
import subprocess
import time
import requests
import json
import sys
from pathlib import Path
import threading
import signal
import os
class VWBTestServer:
"""Serveur de test pour le backend VWB"""
def __init__(self):
self.process = None
self.port = 5004
self.is_running = False
def start(self):
"""Démarrer le serveur backend"""
print(f"🚀 Démarrage du serveur backend sur le port {self.port}...")
try:
# Démarrer le serveur backend
backend_path = Path("visual_workflow_builder/backend")
if not backend_path.exists():
print("❌ Répertoire backend non trouvé")
return False
# Utiliser le script de démarrage existant
script_path = Path("scripts/start_vwb_backend_catalogue_complet_10jan2026.py")
if script_path.exists():
self.process = subprocess.Popen([
sys.executable, str(script_path)
], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
else:
# Fallback vers démarrage direct
self.process = subprocess.Popen([
sys.executable, "-m", "flask", "run",
"--host", "0.0.0.0", "--port", str(self.port)
], cwd=backend_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env={**os.environ, "FLASK_APP": "app_catalogue_simple.py"})
# Attendre que le serveur démarre
for i in range(30): # 30 secondes max
try:
response = requests.get(f"http://localhost:{self.port}/health", timeout=1)
if response.status_code == 200:
print(f"✅ Serveur backend démarré sur le port {self.port}")
self.is_running = True
return True
except:
time.sleep(1)
print("❌ Timeout lors du démarrage du serveur")
return False
except Exception as e:
print(f"❌ Erreur lors du démarrage du serveur: {e}")
return False
def stop(self):
"""Arrêter le serveur backend"""
if self.process:
print("🛑 Arrêt du serveur backend...")
self.process.terminate()
try:
self.process.wait(timeout=5)
except subprocess.TimeoutExpired:
self.process.kill()
self.is_running = False
def test_backend_health():
"""Tester la santé du backend"""
print("🔍 Test de santé du backend...")
try:
response = requests.get("http://localhost:5004/health", timeout=5)
if response.status_code == 200:
data = response.json()
print(f"✅ Backend en ligne: {data.get('status', 'unknown')}")
return True
else:
print(f"❌ Backend répond avec le code: {response.status_code}")
return False
except Exception as e:
print(f"❌ Erreur de connexion au backend: {e}")
return False
def test_catalog_api():
"""Tester l'API du catalogue"""
print("🔍 Test de l'API catalogue...")
try:
response = requests.get("http://localhost:5004/api/vwb/catalog/actions", timeout=5)
if response.status_code == 200:
data = response.json()
actions = data.get('actions', [])
print(f"✅ API catalogue fonctionnelle: {len(actions)} actions disponibles")
# Afficher quelques actions pour vérification
for action in actions[:3]:
print(f" - {action.get('name', 'Sans nom')} ({action.get('id', 'sans-id')})")
return True
else:
print(f"❌ API catalogue répond avec le code: {response.status_code}")
return False
except Exception as e:
print(f"❌ Erreur lors du test de l'API catalogue: {e}")
return False
def test_frontend_build():
"""Tester la compilation du frontend"""
print("🔍 Test de compilation du frontend...")
frontend_path = Path("visual_workflow_builder/frontend")
if not frontend_path.exists():
print("❌ Répertoire frontend non trouvé")
return False
try:
# Vérifier que les fichiers TypeScript compilent
result = subprocess.run([
"npx", "tsc", "--noEmit"
], cwd=frontend_path, capture_output=True, text=True, timeout=60)
if result.returncode == 0:
print("✅ Frontend compile sans erreurs TypeScript")
return True
else:
print("❌ Erreurs de compilation frontend:")
print(result.stderr)
return False
except Exception as e:
print(f"❌ Erreur lors de la compilation frontend: {e}")
return False
def test_catalog_service_detection():
"""Tester la détection automatique d'URL du service catalogue"""
print("🔍 Test de détection automatique d'URL...")
# Simuler différents scénarios de détection
test_urls = [
"http://localhost:5004",
"http://127.0.0.1:5004",
]
working_urls = []
for url in test_urls:
try:
response = requests.get(f"{url}/health", timeout=2)
if response.status_code == 200:
working_urls.append(url)
print(f"✅ URL fonctionnelle détectée: {url}")
except:
print(f"❌ URL non accessible: {url}")
if working_urls:
print(f"✅ Détection automatique réussie: {len(working_urls)} URL(s) fonctionnelle(s)")
return True
else:
print("❌ Aucune URL fonctionnelle détectée")
return False
def test_static_fallback():
"""Tester le fallback vers le catalogue statique"""
print("🔍 Test du fallback catalogue statique...")
# Lire le fichier du catalogue statique
static_catalog_path = Path("visual_workflow_builder/frontend/src/data/staticCatalog.ts")
if not static_catalog_path.exists():
print("❌ Catalogue statique non trouvé")
return False
content = static_catalog_path.read_text()
# Vérifier que les actions de base sont présentes
required_actions = [
"click_anchor",
"type_text",
"wait_for_anchor",
"extract_text",
"hotkey"
]
missing_actions = []
for action in required_actions:
if action not in content:
missing_actions.append(action)
if missing_actions:
print(f"❌ Actions manquantes dans le catalogue statique: {missing_actions}")
return False
else:
print(f"✅ Catalogue statique complet: {len(required_actions)} actions de base")
return True
def create_test_html():
"""Créer une page HTML de test pour le navigateur"""
print("🔍 Création de la page de test navigateur...")
html_content = """<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test Palette Cross-Machine VWB</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background: #0f172a;
color: #e2e8f0;
}
.test-container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: #1e293b;
border-radius: 12px;
border: 1px solid #334155;
}
.status {
padding: 10px;
margin: 10px 0;
border-radius: 8px;
font-weight: bold;
}
.success { background: #22c55e; color: white; }
.error { background: #ef4444; color: white; }
.warning { background: #f59e0b; color: white; }
.info { background: #3b82f6; color: white; }
button {
background: #1976d2;
color: white;
border: none;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
margin: 5px;
}
button:hover {
background: #1565c0;
}
#results {
margin-top: 20px;
padding: 15px;
background: #334155;
border-radius: 8px;
}
</style>
</head>
<body>
<div class="test-container">
<h1>🧪 Test Palette Cross-Machine VWB</h1>
<p>Cette page teste la détection automatique d'URL et le fallback statique de la palette d'outils.</p>
<div class="status info">
📍 URL actuelle: <span id="currentUrl"></span>
</div>
<div>
<button onclick="testCatalogService()">🔍 Tester Service Catalogue</button>
<button onclick="testStaticFallback()">📦 Tester Fallback Statique</button>
<button onclick="testUrlDetection()">🌐 Tester Détection URL</button>
<button onclick="clearResults()">🧹 Effacer Résultats</button>
</div>
<div id="results"></div>
</div>
<script>
// Afficher l'URL actuelle
document.getElementById('currentUrl').textContent = window.location.href;
// Simuler le service catalogue (version simplifiée)
class TestCatalogService {
constructor() {
this.urls = [
window.location.origin,
'http://localhost:5004',
'http://127.0.0.1:5004'
];
this.staticActions = [
{ id: 'click_anchor', name: 'Cliquer sur Ancre', category: 'vision_ui' },
{ id: 'type_text', name: 'Saisir Texte', category: 'vision_ui' },
{ id: 'wait_for_anchor', name: 'Attendre Ancre', category: 'control' },
{ id: 'extract_text', name: 'Extraire Texte', category: 'data' },
{ id: 'hotkey', name: 'Raccourci Clavier', category: 'control' }
];
}
async testUrl(url) {
try {
const response = await fetch(`${url}/health`, {
method: 'GET',
timeout: 2000
});
return response.ok;
} catch (error) {
return false;
}
}
async detectWorkingUrl() {
for (const url of this.urls) {
if (await this.testUrl(url)) {
return url;
}
}
return null;
}
getStaticActions() {
return this.staticActions;
}
}
const catalogService = new TestCatalogService();
function addResult(message, type = 'info') {
const results = document.getElementById('results');
const div = document.createElement('div');
div.className = `status ${type}`;
div.innerHTML = message;
results.appendChild(div);
}
async function testCatalogService() {
addResult('🔍 Test du service catalogue en cours...', 'info');
const workingUrl = await catalogService.detectWorkingUrl();
if (workingUrl) {
addResult(`✅ Service catalogue détecté sur: ${workingUrl}`, 'success');
// Tester l'API catalogue
try {
const response = await fetch(`${workingUrl}/api/vwb/catalog/actions`);
if (response.ok) {
const data = await response.json();
addResult(`✅ API catalogue fonctionnelle: ${data.actions?.length || 0} actions`, 'success');
} else {
addResult(`❌ API catalogue non accessible (${response.status})`, 'error');
}
} catch (error) {
addResult(`❌ Erreur API catalogue: ${error.message}`, 'error');
}
} else {
addResult('❌ Aucun service catalogue détecté', 'error');
}
}
function testStaticFallback() {
addResult('📦 Test du fallback statique...', 'info');
const staticActions = catalogService.getStaticActions();
if (staticActions.length > 0) {
addResult(`✅ Catalogue statique disponible: ${staticActions.length} actions`, 'success');
staticActions.forEach(action => {
addResult(` - ${action.name} (${action.id})`, 'info');
});
} else {
addResult('❌ Catalogue statique vide', 'error');
}
}
async function testUrlDetection() {
addResult('🌐 Test de détection automatique d\'URL...', 'info');
for (const url of catalogService.urls) {
addResult(`⏳ Test de ${url}...`, 'info');
const isWorking = await catalogService.testUrl(url);
if (isWorking) {
addResult(`✅ ${url} accessible`, 'success');
} else {
addResult(`❌ ${url} non accessible`, 'error');
}
}
}
function clearResults() {
document.getElementById('results').innerHTML = '';
}
// Test automatique au chargement
window.addEventListener('load', () => {
addResult('🚀 Page de test chargée - Prêt pour les tests', 'success');
});
</script>
</body>
</html>"""
test_file = Path("test_palette_cross_machine_navigateur.html")
test_file.write_text(html_content)
print(f"✅ Page de test créée: {test_file.absolute()}")
return test_file
def main():
"""Fonction principale de test"""
print("🚀 Test Palette Cross-Machine dans Navigateur - 10 janvier 2026")
print("=" * 70)
server = VWBTestServer()
try:
# Tests préliminaires
tests = [
("Compilation Frontend", test_frontend_build),
("Catalogue Statique", test_static_fallback),
]
passed = 0
for test_name, test_func in tests:
print(f"\n🔍 {test_name}...")
if test_func():
passed += 1
else:
print(f"❌ Échec du test: {test_name}")
# Démarrer le serveur pour les tests réseau
print(f"\n🚀 Démarrage du serveur de test...")
if server.start():
# Tests avec serveur
network_tests = [
("Santé Backend", test_backend_health),
("API Catalogue", test_catalog_api),
("Détection URL", test_catalog_service_detection),
]
for test_name, test_func in network_tests:
print(f"\n🔍 {test_name}...")
if test_func():
passed += 1
else:
print(f"❌ Échec du test: {test_name}")
total_tests = len(tests) + len(network_tests)
else:
print("❌ Impossible de démarrer le serveur - tests réseau ignorés")
total_tests = len(tests)
# Créer la page de test navigateur
print(f"\n🌐 Création de la page de test navigateur...")
test_file = create_test_html()
print("\n" + "=" * 70)
print(f"📊 Résultats: {passed}/{total_tests} tests passés")
if passed == total_tests:
print("✅ TOUS LES TESTS PASSENT")
print(f"\n🌐 Ouvrez le fichier suivant dans votre navigateur pour tester:")
print(f" file://{test_file.absolute()}")
print(f"\n💡 Instructions:")
print(f" 1. Ouvrez le fichier HTML dans votre navigateur")
print(f" 2. Cliquez sur les boutons de test")
print(f" 3. Vérifiez que la détection d'URL fonctionne")
print(f" 4. Vérifiez que le fallback statique fonctionne")
return True
else:
print("❌ CERTAINS TESTS ONT ÉCHOUÉ")
return False
finally:
# Arrêter le serveur
server.stop()
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)