#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Tests de stabilité simplifiés - Visual Workflow Builder Frontend V2 Auteur : Dom, Alice, Kiro - 09 janvier 2026 Script de validation sans dépendance pytest. """ import os import re import sys from pathlib import Path # Chemin vers le frontend VWB SCRIPT_DIR = Path(__file__).parent PROJECT_ROOT = SCRIPT_DIR.parent.parent FRONTEND_PATH = PROJECT_ROOT / "visual_workflow_builder" / "frontend" SRC_PATH = FRONTEND_PATH / "src" def test_api_client_initial_state_is_offline(): """Vérifie que l'état initial du client API est 'offline'.""" api_client_path = SRC_PATH / "services" / "apiClient.ts" if not api_client_path.exists(): return False, f"Fichier non trouvé: {api_client_path}" content = api_client_path.read_text(encoding='utf-8') # Vérifier que l'état initial est 'offline' et non 'checking' if "connectionState: ConnectionState = 'offline'" not in content: return False, "L'état initial du client API doit être 'offline'" if "connectionState: ConnectionState = 'checking'" in content: return False, "L'état initial ne doit PAS être 'checking'" return True, "OK" def test_api_client_lazy_initialization(): """Vérifie que l'initialisation est paresseuse (lazy).""" api_client_path = SRC_PATH / "services" / "apiClient.ts" content = api_client_path.read_text(encoding='utf-8') # Vérifier la présence du commentaire sur l'initialisation paresseuse if "paresseuse" not in content.lower() and "lazy" not in content.lower(): return False, "Le code doit mentionner l'initialisation paresseuse (lazy)" return True, "OK" def test_api_client_async_notifications(): """Vérifie que les notifications sont asynchrones (setTimeout).""" api_client_path = SRC_PATH / "services" / "apiClient.ts" content = api_client_path.read_text(encoding='utf-8') # Vérifier la présence de setTimeout pour les notifications if 'setTimeout' not in content: return False, "Les notifications doivent être asynchrones (setTimeout)" return True, "OK" def test_connection_status_hook_initial_state(): """Vérifie que useConnectionStatus a un état initial 'offline'.""" hook_path = SRC_PATH / "hooks" / "useConnectionStatus.ts" if not hook_path.exists(): return False, f"Fichier non trouvé: {hook_path}" content = hook_path.read_text(encoding='utf-8') # Vérifier que l'état initial est 'offline' if "status: 'offline'" not in content: return False, "L'état initial du hook doit être 'offline'" return True, "OK" def test_connection_status_hook_uses_refs(): """Vérifie que le hook utilise des refs pour les callbacks.""" hook_path = SRC_PATH / "hooks" / "useConnectionStatus.ts" content = hook_path.read_text(encoding='utf-8') if 'useRef' not in content: return False, "Le hook doit utiliser useRef pour éviter les re-renders" return True, "OK" def test_connection_status_hook_initial_state_constant(): """Vérifie que l'état initial est une constante stable.""" hook_path = SRC_PATH / "hooks" / "useConnectionStatus.ts" content = hook_path.read_text(encoding='utf-8') if 'INITIAL_STATE' not in content: return False, "L'état initial doit être une constante INITIAL_STATE" return True, "OK" def test_use_api_client_hook_initial_offline(): """Vérifie que useConnectionState a un état initial 'offline'.""" hook_path = SRC_PATH / "hooks" / "useApiClient.ts" if not hook_path.exists(): return False, f"Fichier non trouvé: {hook_path}" content = hook_path.read_text(encoding='utf-8') # Vérifier que l'état initial est 'offline' if "'offline'" not in content: return False, "useConnectionState doit avoir un état initial 'offline'" return True, "OK" def test_workflow_manager_uses_connection_state(): """Vérifie que WorkflowManager utilise useConnectionState.""" component_path = SRC_PATH / "components" / "WorkflowManager" / "index.tsx" if not component_path.exists(): return False, f"Fichier non trouvé: {component_path}" content = component_path.read_text(encoding='utf-8') if 'useConnectionState' not in content: return False, "WorkflowManager doit utiliser useConnectionState" return True, "OK" def test_executor_uses_connection_status(): """Vérifie que Executor utilise useConnectionStatus.""" component_path = SRC_PATH / "components" / "Executor" / "index.tsx" if not component_path.exists(): return False, f"Fichier non trouvé: {component_path}" content = component_path.read_text(encoding='utf-8') if 'useConnectionStatus' not in content: return False, "Executor doit utiliser useConnectionStatus" return True, "OK" def test_french_comments_in_api_client(): """Vérifie que apiClient.ts a des commentaires en français.""" api_client_path = SRC_PATH / "services" / "apiClient.ts" content = api_client_path.read_text(encoding='utf-8') french_words = ['Auteur', 'janvier', 'gestion', 'connexion', 'hors ligne'] found_french = any(word in content for word in french_words) if not found_french: return False, "apiClient.ts doit avoir des commentaires en français" return True, "OK" def test_typescript_syntax_balanced(): """Vérifie la syntaxe TypeScript basique.""" files_to_check = [ SRC_PATH / "services" / "apiClient.ts", SRC_PATH / "hooks" / "useApiClient.ts", SRC_PATH / "hooks" / "useConnectionStatus.ts", ] for file_path in files_to_check: if not file_path.exists(): continue content = file_path.read_text(encoding='utf-8') if content.count('{') != content.count('}'): return False, f"Accolades non équilibrées dans {file_path.name}" if content.count('(') != content.count(')'): return False, f"Parenthèses non équilibrées dans {file_path.name}" return True, "OK" def run_all_tests(): """Exécute tous les tests et affiche les résultats.""" tests = [ ("État initial apiClient = 'offline'", test_api_client_initial_state_is_offline), ("Initialisation paresseuse (lazy)", test_api_client_lazy_initialization), ("Notifications asynchrones (setTimeout)", test_api_client_async_notifications), ("useConnectionStatus état initial 'offline'", test_connection_status_hook_initial_state), ("useConnectionStatus utilise useRef", test_connection_status_hook_uses_refs), ("useConnectionStatus INITIAL_STATE constant", test_connection_status_hook_initial_state_constant), ("useApiClient état initial 'offline'", test_use_api_client_hook_initial_offline), ("WorkflowManager utilise useConnectionState", test_workflow_manager_uses_connection_state), ("Executor utilise useConnectionStatus", test_executor_uses_connection_status), ("Commentaires français dans apiClient", test_french_comments_in_api_client), ("Syntaxe TypeScript équilibrée", test_typescript_syntax_balanced), ] print("=" * 70) print("Tests de Stabilité - Visual Workflow Builder Frontend V2") print("Auteur : Dom, Alice, Kiro - 09 janvier 2026") print("=" * 70) print() passed = 0 failed = 0 for name, test_func in tests: try: success, message = test_func() if success: print(f"✅ PASS: {name}") passed += 1 else: print(f"❌ FAIL: {name}") print(f" Raison: {message}") failed += 1 except Exception as e: print(f"❌ ERROR: {name}") print(f" Exception: {e}") failed += 1 print() print("=" * 70) print(f"Résultats: {passed} passés, {failed} échoués sur {len(tests)} tests") print("=" * 70) return failed == 0 if __name__ == "__main__": success = run_all_tests() sys.exit(0 if success else 1)