#!/usr/bin/env python3 """ Script de validation - Intégration complète de l'interface des propriétés Auteur : Dom, Alice, Kiro - 12 janvier 2026 Ce script valide l'intégration complète de tous les composants de l'interface des propriétés d'étapes après la Tâche 5 (intégration dans PropertiesPanel). Composants validés : - ParameterFieldRenderer (Tâche 1) - StandardParametersEditor (Tâche 2) - VWBActionProperties amélioré (Tâche 3) - EmptyStateMessage et LoadingState (Tâche 4) - Intégration complète dans PropertiesPanel (Tâche 5) """ import os import sys import json import subprocess from pathlib import Path from typing import Dict, List, Any, Optional # Configuration PROJECT_ROOT = Path(__file__).parent.parent FRONTEND_PATH = PROJECT_ROOT / "visual_workflow_builder" / "frontend" COMPONENTS_PATH = FRONTEND_PATH / "src" / "components" / "PropertiesPanel" HOOKS_PATH = FRONTEND_PATH / "src" / "hooks" TESTS_PATH = PROJECT_ROOT / "tests" / "property" class IntegrationValidator: """Validateur pour l'intégration complète de l'interface des propriétés""" def __init__(self): self.results: List[Dict[str, Any]] = [] def validate_complete_file_structure(self) -> Dict[str, Any]: """Valide la structure complète des fichiers après intégration""" result = { 'name': 'Structure complète des fichiers', 'success': False, 'errors': [], 'warnings': [], 'details': {} } # Tous les fichiers requis après Tâche 5 required_files = [ # Composants principaux COMPONENTS_PATH / "ParameterFieldRenderer.tsx", COMPONENTS_PATH / "StandardParametersEditor.tsx", COMPONENTS_PATH / "VWBActionProperties.tsx", COMPONENTS_PATH / "EmptyStateMessage.tsx", COMPONENTS_PATH / "LoadingState.tsx", COMPONENTS_PATH / "index.tsx", # PropertiesPanel intégré # Hooks HOOKS_PATH / "useAutoSave.ts", # Tests de propriétés TESTS_PATH / "test_parameter_field_renderer_properties_12jan2026.py", TESTS_PATH / "test_standard_parameters_editor_properties_12jan2026.py", TESTS_PATH / "test_auto_save_properties_12jan2026.py", TESTS_PATH / "test_vwb_action_properties_12jan2026.py", TESTS_PATH / "test_empty_state_message_properties_12jan2026.py", TESTS_PATH / "test_loading_state_properties_12jan2026.py", ] for file_path in required_files: if not file_path.exists(): result['errors'].append(f"Fichier manquant: {file_path.relative_to(PROJECT_ROOT)}") else: # Vérifier la taille du fichier file_size = file_path.stat().st_size if file_size < 1024: # Moins de 1KB result['warnings'].append(f"Fichier très petit: {file_path.name} ({file_size} bytes)") result['details'][f"size_{file_path.name}"] = file_size result['success'] = len(result['errors']) == 0 return result def validate_properties_panel_integration(self) -> Dict[str, Any]: """Valide l'intégration dans PropertiesPanel""" result = { 'name': 'Intégration PropertiesPanel', 'success': False, 'errors': [], 'warnings': [], 'details': {} } properties_panel_path = COMPONENTS_PATH / "index.tsx" if not properties_panel_path.exists(): result['errors'].append("PropertiesPanel principal manquant") return result try: content = properties_panel_path.read_text(encoding='utf-8') # Vérifier les imports des nouveaux composants required_imports = [ 'StandardParametersEditor', 'EmptyStateMessage', 'LoadingState', 'StepResolutionLoading', 'VWBActionLoading', 'useStepParametersAutoSave' ] for import_name in required_imports: if import_name in content: result['details'][f"import_{import_name}"] = True else: result['errors'].append(f"Import manquant: {import_name}") # Vérifier la logique de rendu conditionnel conditional_logic_checks = [ 'getDisplayState', 'displayState.type', 'case \'loading\'', 'case \'empty\'', 'case \'vwb-properties\'', 'case \'standard-parameters\'' ] for check in conditional_logic_checks: if check in content: result['details'][f"logic_{check.replace(' ', '_').replace('\'', '')}"] = True else: result['warnings'].append(f"Logique conditionnelle manquante: {check}") # Vérifier l'intégration de l'auto-sauvegarde autosave_checks = [ 'autoSave.triggerSave', 'autoSave.saveState', 'handleValidationChange' ] for check in autosave_checks: if check in content: result['details'][f"autosave_{check.replace('.', '_')}"] = True else: result['warnings'].append(f"Intégration auto-sauvegarde manquante: {check}") # Vérifier la suppression de l'ancien code deprecated_elements = [ 'renderParameterField', 'TextField', 'FormControl', 'Switch' ] for element in deprecated_elements: if element in content: result['warnings'].append(f"Élément obsolète encore présent: {element}") result['success'] = len(result['errors']) == 0 except Exception as e: result['errors'].append(f"Erreur lecture PropertiesPanel: {str(e)}") result['success'] = False return result def validate_component_exports(self) -> Dict[str, Any]: """Valide les exports de tous les composants""" result = { 'name': 'Exports des composants', 'success': False, 'errors': [], 'warnings': [], 'details': {} } # Vérifications des exports par composant component_exports = [ { 'file': COMPONENTS_PATH / "ParameterFieldRenderer.tsx", 'exports': ['ParameterFieldRenderer', 'fieldRendererRegistry', 'FieldRendererType'], 'default_export': 'ParameterFieldRenderer' }, { 'file': COMPONENTS_PATH / "StandardParametersEditor.tsx", 'exports': ['StandardParametersEditor', 'StandardParametersEditorProps'], 'default_export': 'StandardParametersEditor' }, { 'file': COMPONENTS_PATH / "EmptyStateMessage.tsx", 'exports': ['EmptyStateMessage', 'EmptyStateReason', 'SmartEmptyStateMessage'], 'default_export': 'EmptyStateMessage' }, { 'file': COMPONENTS_PATH / "LoadingState.tsx", 'exports': ['LoadingState', 'LoadingType', 'StepResolutionLoading', 'VWBActionLoading'], 'default_export': 'LoadingState' }, { 'file': HOOKS_PATH / "useAutoSave.ts", 'exports': ['useAutoSave', 'useStepParametersAutoSave', 'useSyncedAutoSave'], 'default_export': 'useAutoSave' } ] for component in component_exports: file_path = component['file'] if not file_path.exists(): result['errors'].append(f"Fichier manquant: {file_path.name}") continue try: content = file_path.read_text(encoding='utf-8') # Vérifier les exports nommés for export_name in component['exports']: if f"export" in content and export_name in content: result['details'][f"export_{file_path.name}_{export_name}"] = True else: result['warnings'].append(f"Export manquant dans {file_path.name}: {export_name}") # Vérifier l'export par défaut default_export = component['default_export'] if f"export default" in content: result['details'][f"default_export_{file_path.name}"] = True else: result['errors'].append(f"Export par défaut manquant dans {file_path.name}") except Exception as e: result['errors'].append(f"Erreur lecture {file_path.name}: {str(e)}") result['success'] = len(result['errors']) == 0 return result def validate_typescript_compilation_complete(self) -> Dict[str, Any]: """Valide la compilation TypeScript complète""" result = { 'name': 'Compilation TypeScript complète', 'success': False, 'errors': [], 'warnings': [], 'details': {} } try: # Compilation globale du projet compile_result = subprocess.run( ["npx", "tsc", "--noEmit", "--project", "."], cwd=FRONTEND_PATH, capture_output=True, text=True, timeout=60 ) result['details']['compilation_exit_code'] = compile_result.returncode result['details']['compilation_stdout'] = compile_result.stdout[:500] # Limiter la sortie result['details']['compilation_stderr'] = compile_result.stderr[:500] if compile_result.returncode == 0: result['success'] = True result['details']['compilation_status'] = 'success' else: result['errors'].append(f"Erreurs de compilation TypeScript: {compile_result.stderr}") result['details']['compilation_status'] = 'failed' except subprocess.TimeoutExpired: result['errors'].append("Timeout lors de la compilation TypeScript") result['details']['compilation_status'] = 'timeout' except Exception as e: result['errors'].append(f"Erreur lors de la compilation: {str(e)}") result['details']['compilation_status'] = 'error' return result def validate_property_tests_execution(self) -> Dict[str, Any]: """Valide l'exécution des tests de propriétés""" result = { 'name': 'Exécution des tests de propriétés', 'success': False, 'errors': [], 'warnings': [], 'details': {} } # Tests de propriétés à exécuter property_test_files = [ "test_parameter_field_renderer_properties_12jan2026.py", "test_standard_parameters_editor_properties_12jan2026.py", "test_auto_save_properties_12jan2026.py", "test_vwb_action_properties_12jan2026.py", "test_empty_state_message_properties_12jan2026.py", "test_loading_state_properties_12jan2026.py" ] successful_tests = 0 for test_file in property_test_files: test_path = TESTS_PATH / test_file if not test_path.exists(): result['errors'].append(f"Test manquant: {test_file}") continue try: # Exécuter le test avec pytest test_result = subprocess.run( ["python", "-m", "pytest", str(test_path), "-v", "--tb=short"], cwd=PROJECT_ROOT, capture_output=True, text=True, timeout=30 ) result['details'][f"test_{test_file}_exit_code"] = test_result.returncode if test_result.returncode == 0: successful_tests += 1 result['details'][f"test_{test_file}_status"] = 'passed' else: result['warnings'].append(f"Test échoué: {test_file}") result['details'][f"test_{test_file}_status"] = 'failed' result['details'][f"test_{test_file}_stderr"] = test_result.stderr[:200] except subprocess.TimeoutExpired: result['warnings'].append(f"Timeout test: {test_file}") result['details'][f"test_{test_file}_status"] = 'timeout' except Exception as e: result['warnings'].append(f"Erreur test {test_file}: {str(e)}") result['details'][f"test_{test_file}_status"] = 'error' result['details']['successful_tests'] = successful_tests result['details']['total_tests'] = len(property_test_files) # Succès si au moins 80% des tests passent success_rate = successful_tests / len(property_test_files) result['success'] = success_rate >= 0.8 result['details']['success_rate'] = f"{success_rate * 100:.1f}%" return result def run_complete_validation(self) -> Dict[str, Any]: """Exécute la validation complète de l'intégration""" print("🔍 Validation complète de l'intégration - Interface Propriétés d'Étapes") print("=" * 80) # Exécuter toutes les validations validations = [ self.validate_complete_file_structure, self.validate_properties_panel_integration, self.validate_component_exports, self.validate_typescript_compilation_complete, self.validate_property_tests_execution, ] for validation_func in validations: print(f"\n📋 {validation_func.__name__.replace('validate_', '').replace('_', ' ').title()}...") result = validation_func() self.results.append(result) if result['success']: print(f"✅ {result['name']} - Succès") else: print(f"❌ {result['name']} - Échec") # Afficher les erreurs for error in result['errors']: print(f" 🔴 {error}") # Afficher les avertissements for warning in result['warnings']: print(f" 🟡 {warning}") # Résumé global print("\n" + "=" * 80) print("📊 RÉSUMÉ DE VALIDATION COMPLÈTE") print("=" * 80) total_validations = len(self.results) successful_validations = sum(1 for r in self.results if r['success']) total_errors = sum(len(r['errors']) for r in self.results) total_warnings = sum(len(r['warnings']) for r in self.results) print(f"Validations réussies: {successful_validations}/{total_validations}") print(f"Erreurs totales: {total_errors}") print(f"Avertissements totaux: {total_warnings}") # Statut global global_success = successful_validations == total_validations and total_errors == 0 if global_success: print("\n🎉 INTÉGRATION COMPLÈTE RÉUSSIE") print("✅ Tous les composants sont intégrés et fonctionnels") print("🚀 Prêt pour les fonctionnalités avancées (Tâches 7-13)") else: print("\n⚠️ INTÉGRATION PARTIELLEMENT RÉUSSIE") print("🔧 Corrections mineures recommandées") if successful_validations >= total_validations * 0.8: print("📈 Intégration majoritairement fonctionnelle") # Prochaines étapes print("\n📋 PROCHAINES ÉTAPES RECOMMANDÉES:") print("1. Implémenter les fonctionnalités avancées de validation (Tâche 7)") print("2. Optimiser les performances et l'accessibilité (Tâche 8)") print("3. Assurer la cohérence visuelle et le design system (Tâche 9)") print("4. Vérifier la compatibilité et l'intégration système (Tâche 10)") return { "global_success": global_success, "successful_validations": successful_validations, "total_validations": total_validations, "total_errors": total_errors, "total_warnings": total_warnings, "integration_ready": successful_validations >= total_validations * 0.8, "results": self.results } def main(): """Fonction principale""" validator = IntegrationValidator() results = validator.run_complete_validation() # Sauvegarder les résultats results_file = PROJECT_ROOT / "validation_integration_complete_proprietes_12jan2026.json" with open(results_file, 'w', encoding='utf-8') as f: json.dump(results, f, indent=2, ensure_ascii=False) print(f"\n💾 Résultats sauvegardés dans: {results_file}") # Code de sortie sys.exit(0 if results["integration_ready"] else 1) if __name__ == "__main__": main()