- 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>
319 lines
12 KiB
Python
319 lines
12 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Script de Validation Finale - Intégration Propriétés VWB
|
|
Auteur : Dom, Alice, Kiro - 10 janvier 2026
|
|
|
|
Ce script valide l'intégration complète des propriétés d'étapes VWB
|
|
dans le Visual Workflow Builder sans dépendances pytest.
|
|
"""
|
|
|
|
import json
|
|
import time
|
|
import requests
|
|
import subprocess
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Dict, Any, List, Optional
|
|
|
|
# Configuration des chemins
|
|
PROJECT_ROOT = Path(__file__).parent.parent
|
|
VWB_FRONTEND_PATH = PROJECT_ROOT / "visual_workflow_builder" / "frontend"
|
|
VWB_BACKEND_PATH = PROJECT_ROOT / "visual_workflow_builder" / "backend"
|
|
|
|
class ValidationFinaleProprietesVWB:
|
|
"""Validation finale de l'intégration des propriétés VWB"""
|
|
|
|
def __init__(self):
|
|
self.backend_url = "http://localhost:5004"
|
|
self.backend_process = None
|
|
self.tests_passed = 0
|
|
self.tests_failed = 0
|
|
self.errors = []
|
|
|
|
def run_all_validations(self):
|
|
"""Exécuter toutes les validations"""
|
|
print("🚀 VALIDATION FINALE - INTÉGRATION PROPRIÉTÉS VWB")
|
|
print("=" * 60)
|
|
|
|
try:
|
|
# Étape 1: Vérifier l'environnement
|
|
self.validate_environment()
|
|
|
|
# Étape 2: Démarrer le backend
|
|
self.start_backend()
|
|
|
|
# Étape 3: Valider les fichiers frontend
|
|
self.validate_frontend_files()
|
|
|
|
# Étape 4: Valider l'API backend
|
|
self.validate_backend_api()
|
|
|
|
# Étape 5: Valider l'intégration complète
|
|
self.validate_integration()
|
|
|
|
except Exception as e:
|
|
self.log_error(f"Erreur critique: {e}")
|
|
|
|
finally:
|
|
# Nettoyage
|
|
self.cleanup()
|
|
|
|
# Rapport final
|
|
self.print_final_report()
|
|
|
|
def validate_environment(self):
|
|
"""Valider l'environnement de développement"""
|
|
print("\n🔍 ÉTAPE 1: Validation de l'environnement")
|
|
|
|
# Vérifier l'environnement virtuel
|
|
if "venv_v3" not in sys.executable:
|
|
self.log_error("Environnement virtuel venv_v3 non activé")
|
|
return
|
|
|
|
self.log_success("Environnement virtuel venv_v3 activé")
|
|
|
|
# Vérifier les dépendances Python
|
|
try:
|
|
import flask
|
|
import requests
|
|
self.log_success("Dépendances Python disponibles")
|
|
except ImportError as e:
|
|
self.log_error(f"Dépendances manquantes: {e}")
|
|
|
|
def start_backend(self):
|
|
"""Démarrer le backend VWB"""
|
|
print("\n🔍 ÉTAPE 2: Démarrage du backend VWB")
|
|
|
|
try:
|
|
# Vérifier si le backend est déjà en cours d'exécution
|
|
try:
|
|
response = requests.get(f"{self.backend_url}/api/health", timeout=2)
|
|
if response.status_code == 200:
|
|
self.log_success("Backend VWB déjà en cours d'exécution")
|
|
return
|
|
except requests.exceptions.RequestException:
|
|
pass
|
|
|
|
# Démarrer le backend
|
|
script_path = PROJECT_ROOT / "scripts" / "start_vwb_backend_catalogue_complet_10jan2026.py"
|
|
if script_path.exists():
|
|
self.backend_process = subprocess.Popen([
|
|
sys.executable, str(script_path)
|
|
], cwd=str(PROJECT_ROOT))
|
|
else:
|
|
# Fallback
|
|
self.backend_process = subprocess.Popen([
|
|
sys.executable, "-m", "visual_workflow_builder.backend.app_catalogue_simple"
|
|
], cwd=str(PROJECT_ROOT))
|
|
|
|
# Attendre que le backend soit prêt
|
|
max_attempts = 30
|
|
for attempt in range(max_attempts):
|
|
try:
|
|
response = requests.get(f"{self.backend_url}/api/health", timeout=2)
|
|
if response.status_code == 200:
|
|
self.log_success(f"Backend VWB démarré (PID: {self.backend_process.pid})")
|
|
return
|
|
except requests.exceptions.RequestException:
|
|
pass
|
|
|
|
time.sleep(1)
|
|
|
|
self.log_error("Backend VWB non accessible après 30 secondes")
|
|
|
|
except Exception as e:
|
|
self.log_error(f"Impossible de démarrer le backend VWB: {e}")
|
|
|
|
def validate_frontend_files(self):
|
|
"""Valider les fichiers frontend"""
|
|
print("\n🔍 ÉTAPE 3: Validation des fichiers frontend")
|
|
|
|
# Fichiers essentiels à vérifier
|
|
essential_files = [
|
|
# Types
|
|
VWB_FRONTEND_PATH / "src" / "types" / "catalog.ts",
|
|
VWB_FRONTEND_PATH / "src" / "types" / "index.ts",
|
|
|
|
# Services
|
|
VWB_FRONTEND_PATH / "src" / "services" / "catalogService.ts",
|
|
|
|
# Hooks
|
|
VWB_FRONTEND_PATH / "src" / "hooks" / "useVWBStepIntegration.ts",
|
|
|
|
# Composants
|
|
VWB_FRONTEND_PATH / "src" / "components" / "PropertiesPanel" / "VWBActionProperties.tsx",
|
|
VWB_FRONTEND_PATH / "src" / "components" / "PropertiesPanel" / "index.tsx",
|
|
VWB_FRONTEND_PATH / "src" / "components" / "Canvas" / "StepNode.tsx",
|
|
VWB_FRONTEND_PATH / "src" / "components" / "Palette" / "index.tsx",
|
|
]
|
|
|
|
for file_path in essential_files:
|
|
if file_path.exists():
|
|
self.log_success(f"Fichier présent: {file_path.name}")
|
|
else:
|
|
self.log_error(f"Fichier manquant: {file_path}")
|
|
|
|
# Vérifier le contenu des fichiers clés
|
|
self.validate_file_content()
|
|
|
|
def validate_file_content(self):
|
|
"""Valider le contenu des fichiers clés"""
|
|
print("\n🔍 Validation du contenu des fichiers")
|
|
|
|
# Vérifier catalog.ts
|
|
catalog_types_file = VWB_FRONTEND_PATH / "src" / "types" / "catalog.ts"
|
|
if catalog_types_file.exists():
|
|
content = catalog_types_file.read_text()
|
|
required_types = ["VWBCatalogAction", "VWBActionParameter", "VWBVisualAnchor"]
|
|
|
|
for type_name in required_types:
|
|
if type_name in content:
|
|
self.log_success(f"Type {type_name} présent")
|
|
else:
|
|
self.log_error(f"Type {type_name} manquant")
|
|
|
|
# Vérifier VWBActionProperties.tsx
|
|
vwb_props_file = VWB_FRONTEND_PATH / "src" / "components" / "PropertiesPanel" / "VWBActionProperties.tsx"
|
|
if vwb_props_file.exists():
|
|
content = vwb_props_file.read_text()
|
|
required_elements = ["VWBActionProperties", "VisualAnchorEditor", "onParameterChange"]
|
|
|
|
for element in required_elements:
|
|
if element in content:
|
|
self.log_success(f"Élément {element} présent dans VWBActionProperties")
|
|
else:
|
|
self.log_error(f"Élément {element} manquant dans VWBActionProperties")
|
|
|
|
# Vérifier l'intégration dans PropertiesPanel/index.tsx
|
|
main_props_file = VWB_FRONTEND_PATH / "src" / "components" / "PropertiesPanel" / "index.tsx"
|
|
if main_props_file.exists():
|
|
content = main_props_file.read_text()
|
|
integration_elements = ["import VWBActionProperties", "useVWBStepIntegration", "isVWBCatalogAction"]
|
|
|
|
for element in integration_elements:
|
|
if element in content:
|
|
self.log_success(f"Intégration {element} présente")
|
|
else:
|
|
self.log_error(f"Intégration {element} manquante")
|
|
|
|
def validate_backend_api(self):
|
|
"""Valider l'API backend"""
|
|
print("\n🔍 ÉTAPE 4: Validation de l'API backend")
|
|
|
|
try:
|
|
# Test de l'endpoint catalogue
|
|
response = requests.get(f"{self.backend_url}/api/vwb/catalog/actions", timeout=5)
|
|
if response.status_code == 200:
|
|
self.log_success("Endpoint catalogue accessible")
|
|
|
|
catalog_data = response.json()
|
|
if "actions" in catalog_data:
|
|
actions = catalog_data["actions"]
|
|
self.log_success(f"Catalogue contient {len(actions)} actions")
|
|
|
|
# Vérifier les actions essentielles
|
|
action_ids = [action["id"] for action in actions]
|
|
required_actions = ["click_anchor", "type_text", "wait_for_anchor"]
|
|
|
|
for action_id in required_actions:
|
|
if action_id in action_ids:
|
|
self.log_success(f"Action {action_id} disponible")
|
|
else:
|
|
self.log_error(f"Action {action_id} manquante")
|
|
else:
|
|
self.log_error("Structure de catalogue invalide")
|
|
else:
|
|
self.log_error(f"Endpoint catalogue non accessible: {response.status_code}")
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
self.log_error(f"Erreur de connexion API: {e}")
|
|
|
|
def validate_integration(self):
|
|
"""Valider l'intégration complète"""
|
|
print("\n🔍 ÉTAPE 5: Validation de l'intégration complète")
|
|
|
|
try:
|
|
# Test de validation d'action
|
|
validation_request = {
|
|
"type": "click_anchor",
|
|
"parameters": {
|
|
"visual_anchor": {
|
|
"anchor_type": "screenshot",
|
|
"screenshot_base64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==",
|
|
"confidence_threshold": 0.8
|
|
}
|
|
}
|
|
}
|
|
|
|
response = requests.post(
|
|
f"{self.backend_url}/api/vwb/catalog/validate",
|
|
json=validation_request,
|
|
timeout=5
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
validation_result = response.json()
|
|
if validation_result.get("is_valid"):
|
|
self.log_success("Validation d'action fonctionnelle")
|
|
else:
|
|
self.log_error("Validation d'action échouée")
|
|
else:
|
|
self.log_error(f"Endpoint de validation non accessible: {response.status_code}")
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
self.log_error(f"Erreur de validation: {e}")
|
|
|
|
def cleanup(self):
|
|
"""Nettoyage des ressources"""
|
|
if self.backend_process:
|
|
try:
|
|
self.backend_process.terminate()
|
|
self.backend_process.wait(timeout=5)
|
|
except subprocess.TimeoutExpired:
|
|
self.backend_process.kill()
|
|
|
|
def log_success(self, message: str):
|
|
"""Enregistrer un succès"""
|
|
print(f"✅ {message}")
|
|
self.tests_passed += 1
|
|
|
|
def log_error(self, message: str):
|
|
"""Enregistrer une erreur"""
|
|
print(f"❌ {message}")
|
|
self.tests_failed += 1
|
|
self.errors.append(message)
|
|
|
|
def print_final_report(self):
|
|
"""Imprimer le rapport final"""
|
|
print("\n" + "=" * 60)
|
|
print("📊 RAPPORT FINAL DE VALIDATION")
|
|
print("=" * 60)
|
|
|
|
print(f"✅ Tests réussis: {self.tests_passed}")
|
|
print(f"❌ Tests échoués: {self.tests_failed}")
|
|
print(f"📈 Taux de réussite: {(self.tests_passed / (self.tests_passed + self.tests_failed) * 100):.1f}%")
|
|
|
|
if self.errors:
|
|
print("\n🔧 ERREURS À CORRIGER:")
|
|
for i, error in enumerate(self.errors, 1):
|
|
print(f" {i}. {error}")
|
|
|
|
if self.tests_failed == 0:
|
|
print("\n🎉 VALIDATION COMPLÈTE RÉUSSIE!")
|
|
print("✨ L'intégration des propriétés d'étapes VWB est fonctionnelle")
|
|
return True
|
|
else:
|
|
print("\n⚠️ VALIDATION INCOMPLÈTE")
|
|
print("🔧 Veuillez corriger les erreurs identifiées")
|
|
return False
|
|
|
|
def main():
|
|
"""Fonction principale"""
|
|
validator = ValidationFinaleProprietesVWB()
|
|
success = validator.run_all_validations()
|
|
|
|
return 0 if success else 1
|
|
|
|
if __name__ == "__main__":
|
|
exit(main()) |