#!/usr/bin/env python3 """ Utilitaires pour tests de fonctionnalité réelle - Documentation Tab Fournit des fonctions pour tester avec de vraies données et services sans simulation ni mocking. """ import json import requests import time from pathlib import Path from typing import Dict, List, Optional, Any class RealDocumentationService: """Service pour interagir avec la vraie API de documentation""" def __init__(self, base_url: str = "http://localhost:5000"): self.base_url = base_url.rstrip("/") self.session = requests.Session() self.session.timeout = 10 def get_node_types(self) -> Optional[List[Dict[str, Any]]]: """Récupérer les vrais types de nœuds depuis l'API""" try: response = self.session.get(f"{self.base_url}/api/node-types") if response.status_code == 200: return response.json() except requests.RequestException as e: print(f"Erreur API node-types: {e}") return None def get_tool_documentation(self, tool_id: str) -> Optional[Dict[str, Any]]: """Récupérer la documentation d'un outil spécifique""" try: response = self.session.get(f"{self.base_url}/api/tools/{tool_id}/documentation") if response.status_code == 200: return response.json() except requests.RequestException as e: print(f"Erreur API documentation {tool_id}: {e}") return None def validate_documentation_structure(self, doc_data: Dict[str, Any]) -> bool: """Valider que la structure de documentation est correcte""" required_fields = ["title", "description", "parameters"] return all(field in doc_data for field in required_fields) class RealWorkflowService: """Service pour interagir avec les vrais workflows""" def __init__(self, base_url: str = "http://localhost:5000"): self.base_url = base_url.rstrip("/") self.session = requests.Session() self.session.timeout = 10 def create_test_workflow(self) -> Optional[str]: """Créer un vrai workflow de test""" test_workflow = { "name": "Test Documentation Workflow", "description": "Workflow créé pour tester la documentation", "nodes": [ { "id": "node_1", "type": "action", "data": { "label": "Test Action", "action_type": "click", "target": "button" }, "position": {"x": 100, "y": 100} } ], "edges": [] } try: response = self.session.post( f"{self.base_url}/api/workflows", json=test_workflow ) if response.status_code == 201: return response.json().get("id") except requests.RequestException as e: print(f"Erreur création workflow: {e}") return None def delete_test_workflow(self, workflow_id: str) -> bool: """Supprimer un workflow de test""" try: response = self.session.delete(f"{self.base_url}/api/workflows/{workflow_id}") return response.status_code == 204 except requests.RequestException as e: print(f"Erreur suppression workflow: {e}") return False class RealDataProvider: """Fournisseur de données réelles pour les tests""" @staticmethod def get_local_tool_documentation() -> Optional[Dict[str, Any]]: """Charger la vraie documentation locale depuis les fichiers""" doc_file = Path("visual_workflow_builder/frontend/src/data/toolDocumentation.ts") if not doc_file.exists(): return None try: content = doc_file.read_text(encoding='utf-8') # Parser le contenu TypeScript (simple extraction) # Chercher les définitions d'outils tools = {} lines = content.split('\n') current_tool = None for line in lines: line = line.strip() # Détecter le début d'une définition d'outil if line.startswith('"') and '": {' in line: tool_name = line.split('"')[1] current_tool = tool_name tools[tool_name] = {} # Extraire les propriétés elif current_tool and ':' in line and not line.startswith('//'): if 'title:' in line: title = line.split('"')[1] if '"' in line else "" tools[current_tool]['title'] = title elif 'description:' in line: desc = line.split('"')[1] if '"' in line else "" tools[current_tool]['description'] = desc return tools if tools else None except Exception as e: print(f"Erreur lecture documentation locale: {e}") return None @staticmethod def get_real_node_configurations() -> List[Dict[str, Any]]: """Récupérer les vraies configurations de nœuds""" return [ { "type": "action", "label": "Action Node", "category": "basic", "properties": { "action_type": {"type": "select", "options": ["click", "type", "wait"]}, "target": {"type": "string", "required": True}, "value": {"type": "string", "required": False} } }, { "type": "condition", "label": "Condition Node", "category": "logic", "properties": { "condition_type": {"type": "select", "options": ["exists", "visible", "text_contains"]}, "target": {"type": "string", "required": True}, "expected_value": {"type": "string", "required": False} } }, { "type": "loop", "label": "Loop Node", "category": "control", "properties": { "loop_type": {"type": "select", "options": ["for", "while", "foreach"]}, "iterations": {"type": "number", "default": 1}, "condition": {"type": "string", "required": False} } } ] class RealBrowserInteractions: """Interactions réelles avec le navigateur pour les tests""" @staticmethod def simulate_real_user_behavior(driver, duration_seconds: int = 5): """Simuler un comportement utilisateur réaliste""" import random from selenium.webdriver.common.action_chains import ActionChains actions = ActionChains(driver) # Mouvements de souris réalistes for _ in range(duration_seconds): # Mouvement aléatoire de la souris x_offset = random.randint(-50, 50) y_offset = random.randint(-50, 50) actions.move_by_offset(x_offset, y_offset) # Pause réaliste time.sleep(random.uniform(0.5, 1.5)) # Parfois cliquer if random.random() < 0.3: actions.click() actions.perform() actions = ActionChains(driver) # Reset actions @staticmethod def verify_real_dom_state(driver, expected_elements: List[str]) -> Dict[str, bool]: """Vérifier l'état réel du DOM""" results = {} for selector in expected_elements: try: elements = driver.find_elements("css selector", selector) results[selector] = len(elements) > 0 except Exception as e: print(f"Erreur vérification {selector}: {e}") results[selector] = False return results @staticmethod def capture_real_browser_logs(driver) -> List[Dict[str, Any]]: """Capturer les vrais logs du navigateur""" try: logs = driver.get_log('browser') return [ { "level": log['level'], "message": log['message'], "timestamp": log['timestamp'] } for log in logs ] except Exception as e: print(f"Erreur capture logs: {e}") return [] class RealTestValidator: """Validateur pour s'assurer que les tests utilisent de vraies données""" @staticmethod def validate_no_mocks_used(test_function) -> bool: """Vérifier qu'aucun mock n'est utilisé dans le test""" import inspect source = inspect.getsource(test_function) mock_indicators = [ "unittest.mock", "mock.patch", "MagicMock", "Mock()", "@patch", "mock_" ] for indicator in mock_indicators: if indicator in source: print(f"⚠️ Mock détecté: {indicator}") return False return True @staticmethod def validate_real_data_usage(data: Any) -> bool: """Vérifier que les données utilisées sont réelles""" if isinstance(data, dict): # Vérifier qu'il n'y a pas de données factices fake_indicators = ["fake", "mock", "test_", "dummy", "placeholder"] for key, value in data.items(): key_str = str(key).lower() value_str = str(value).lower() for indicator in fake_indicators: if indicator in key_str or indicator in value_str: print(f"⚠️ Données factices détectées: {key}={value}") return False return True @staticmethod def validate_real_service_calls(service_calls: List[str]) -> bool: """Vérifier que les appels de service sont réels""" for call in service_calls: if "localhost" not in call and "127.0.0.1" not in call: if not call.startswith("http"): print(f"⚠️ Appel de service suspect: {call}") return False return True # Fonctions utilitaires pour l'intégration def setup_real_test_environment(): """Configurer un environnement de test avec de vraies données""" doc_service = RealDocumentationService() workflow_service = RealWorkflowService() # Vérifier que les services sont disponibles node_types = doc_service.get_node_types() if node_types: print(f"✅ Service documentation disponible ({len(node_types)} types)") else: print("⚠️ Service documentation non disponible, utilisation données locales") return { "documentation_service": doc_service, "workflow_service": workflow_service, "data_provider": RealDataProvider(), "browser_interactions": RealBrowserInteractions(), "validator": RealTestValidator() } def cleanup_real_test_environment(test_env: Dict[str, Any], created_resources: List[str]): """Nettoyer l'environnement de test""" workflow_service = test_env.get("workflow_service") if workflow_service: for resource_id in created_resources: try: workflow_service.delete_test_workflow(resource_id) print(f"✅ Ressource nettoyée: {resource_id}") except Exception as e: print(f"⚠️ Erreur nettoyage {resource_id}: {e}") if __name__ == "__main__": # Test des utilitaires print("🧪 Test des utilitaires de fonctionnalité réelle") test_env = setup_real_test_environment() # Test du fournisseur de données locales local_docs = RealDataProvider.get_local_tool_documentation() if local_docs: print(f"✅ Documentation locale chargée: {len(local_docs)} outils") else: print("❌ Impossible de charger la documentation locale") # Test des configurations de nœuds node_configs = RealDataProvider.get_real_node_configurations() print(f"✅ Configurations de nœuds: {len(node_configs)} types") print("✅ Utilitaires de test réel validés")