#!/usr/bin/env python3 """ Script de validation - Checkpoint Interface Propriétés d'Étapes Auteur : Dom, Alice, Kiro - 12 janvier 2026 Ce script valide l'implémentation des composants de base de l'interface des propriétés d'étapes selon les spécifications définies. Composants validés : - ParameterFieldRenderer (Tâche 1) - StandardParametersEditor (Tâche 2) - VWBActionProperties amélioré (Tâche 3) """ 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 ValidationResult: """Résultat de validation""" def __init__(self, name: str): self.name = name self.success = False self.errors: List[str] = [] self.warnings: List[str] = [] self.details: Dict[str, Any] = {} def add_error(self, message: str): self.errors.append(message) def add_warning(self, message: str): self.warnings.append(message) def set_success(self, success: bool): self.success = success def add_detail(self, key: str, value: Any): self.details[key] = value class InterfacePropertiesValidator: """Validateur pour l'interface des propriétés d'étapes""" def __init__(self): self.results: List[ValidationResult] = [] def validate_file_structure(self) -> ValidationResult: """Valide la structure des fichiers créés""" result = ValidationResult("Structure des fichiers") # Fichiers requis required_files = [ COMPONENTS_PATH / "ParameterFieldRenderer.tsx", COMPONENTS_PATH / "StandardParametersEditor.tsx", COMPONENTS_PATH / "VWBActionProperties.tsx", HOOKS_PATH / "useAutoSave.ts", ] # Tests de propriétés requis required_tests = [ 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", ] all_files = required_files + required_tests for file_path in all_files: if not file_path.exists(): result.add_error(f"Fichier manquant: {file_path.relative_to(PROJECT_ROOT)}") else: # Vérifier la taille du fichier (doit être > 1KB) file_size = file_path.stat().st_size if file_size < 1024: result.add_warning(f"Fichier très petit: {file_path.name} ({file_size} bytes)") result.add_detail(f"size_{file_path.name}", file_size) result.set_success(len(result.errors) == 0) return result def validate_typescript_compilation(self) -> ValidationResult: """Valide la compilation TypeScript des composants""" result = ValidationResult("Compilation TypeScript") try: # Vérifier si TypeScript est disponible ts_check = subprocess.run( ["npx", "tsc", "--version"], cwd=FRONTEND_PATH, capture_output=True, text=True, timeout=10 ) if ts_check.returncode != 0: result.add_error("TypeScript non disponible") result.set_success(False) return result result.add_detail("typescript_version", ts_check.stdout.strip()) # Compilation des fichiers TypeScript ts_files = [ "src/components/PropertiesPanel/ParameterFieldRenderer.tsx", "src/components/PropertiesPanel/StandardParametersEditor.tsx", "src/hooks/useAutoSave.ts" ] for ts_file in ts_files: compile_result = subprocess.run( ["npx", "tsc", "--noEmit", "--project", "."], cwd=FRONTEND_PATH, capture_output=True, text=True, timeout=30 ) if compile_result.returncode != 0: result.add_error(f"Erreur compilation globale: {compile_result.stderr}") break else: result.add_detail(f"compiled_{Path(ts_file).name}", True) result.set_success(len(result.errors) == 0) except subprocess.TimeoutExpired: result.add_error("Timeout lors de la compilation TypeScript") result.set_success(False) except Exception as e: result.add_error(f"Erreur lors de la validation TypeScript: {str(e)}") result.set_success(False) return result def validate_component_interfaces(self) -> ValidationResult: """Valide les interfaces des composants""" result = ValidationResult("Interfaces des composants") # Vérifier les exports et interfaces dans les fichiers component_checks = [ { "file": COMPONENTS_PATH / "ParameterFieldRenderer.tsx", "exports": ["ParameterFieldRenderer", "fieldRendererRegistry", "FieldRendererType"], "interfaces": ["ParameterFieldRendererProps", "CustomFieldRenderer"] }, { "file": COMPONENTS_PATH / "StandardParametersEditor.tsx", "exports": ["StandardParametersEditor"], "interfaces": ["StandardParametersEditorProps"] }, { "file": HOOKS_PATH / "useAutoSave.ts", "exports": ["useAutoSave", "useStepParametersAutoSave", "useSyncedAutoSave"], "interfaces": ["AutoSaveOptions", "SaveState", "UseAutoSaveResult"] } ] for check in component_checks: file_path = check["file"] if not file_path.exists(): result.add_error(f"Fichier manquant: {file_path.name}") continue try: content = file_path.read_text(encoding='utf-8') # Vérifier les exports for export_name in check["exports"]: if f"export" in content and export_name in content: result.add_detail(f"export_{export_name}", True) else: result.add_warning(f"Export manquant dans {file_path.name}: {export_name}") # Vérifier les interfaces for interface_name in check["interfaces"]: if f"interface {interface_name}" in content: result.add_detail(f"interface_{interface_name}", True) else: result.add_warning(f"Interface manquante dans {file_path.name}: {interface_name}") # Vérifier les commentaires français if "Auteur : Dom, Alice, Kiro" not in content: result.add_warning(f"Attribution d'auteur manquante dans {file_path.name}") if "12 janvier 2026" not in content: result.add_warning(f"Date manquante dans {file_path.name}") except Exception as e: result.add_error(f"Erreur lecture {file_path.name}: {str(e)}") result.set_success(len(result.errors) == 0) return result def validate_property_tests(self) -> ValidationResult: """Valide les tests de propriétés""" result = ValidationResult("Tests de propriétés") test_files = [ 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", ] for test_file in test_files: if not test_file.exists(): result.add_error(f"Test manquant: {test_file.name}") continue try: content = test_file.read_text(encoding='utf-8') # Vérifier la structure des tests de propriétés required_elements = [ "from hypothesis import given", "PROPERTY_TEST_SETTINGS", "Feature: interface-proprietes-etapes-complete", "Property", "Validates: Requirements" ] for element in required_elements: if element in content: result.add_detail(f"has_{element.replace(' ', '_').replace(':', '')}", True) else: result.add_warning(f"Élément manquant dans {test_file.name}: {element}") # Compter les tests de propriétés property_count = content.count("def test_property_") result.add_detail(f"property_tests_{test_file.name}", property_count) if property_count == 0: result.add_error(f"Aucun test de propriété dans {test_file.name}") except Exception as e: result.add_error(f"Erreur lecture test {test_file.name}: {str(e)}") result.set_success(len(result.errors) == 0) return result def validate_integration_readiness(self) -> ValidationResult: """Valide la préparation à l'intégration""" result = ValidationResult("Préparation à l'intégration") # Vérifier que PropertiesPanel existe et peut être modifié properties_panel_path = COMPONENTS_PATH / "index.tsx" if not properties_panel_path.exists(): result.add_error("PropertiesPanel principal manquant") result.set_success(False) return result try: content = properties_panel_path.read_text(encoding='utf-8') # Vérifier les imports nécessaires required_imports = [ "ParameterFieldRenderer", "useStepTypeResolver", "VWBActionProperties" ] for import_name in required_imports: if import_name in content: result.add_detail(f"import_{import_name}", True) else: result.add_warning(f"Import manquant: {import_name}") # Vérifier la structure du composant if "const PropertiesPanel" in content: result.add_detail("component_structure", True) else: result.add_error("Structure de composant invalide") # Vérifier la mémorisation if "memo(PropertiesPanel" in content: result.add_detail("memoization", True) else: result.add_warning("Mémorisation manquante") result.set_success(len(result.errors) == 0) except Exception as e: result.add_error(f"Erreur validation PropertiesPanel: {str(e)}") result.set_success(False) return result def run_validation(self) -> Dict[str, Any]: """Exécute toutes les validations""" print("🔍 Validation de l'interface des propriétés d'étapes - Checkpoint") print("=" * 70) # Exécuter toutes les validations validations = [ self.validate_file_structure, self.validate_typescript_compilation, self.validate_component_interfaces, self.validate_property_tests, self.validate_integration_readiness, ] 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" + "=" * 70) print("📊 RÉSUMÉ DE VALIDATION") print("=" * 70) 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🎉 VALIDATION GLOBALE RÉUSSIE") print("✅ Tous les composants sont prêts pour l'intégration") else: print("\n⚠️ VALIDATION GLOBALE PARTIELLE") print("🔧 Corrections nécessaires avant l'intégration") # Prochaines étapes print("\n📋 PROCHAINES ÉTAPES:") print("1. Créer les composants d'état (EmptyStateMessage, LoadingState)") print("2. Intégrer tous les composants dans PropertiesPanel") print("3. Implémenter les fonctionnalités avancées de validation") print("4. Optimiser les performances et l'accessibilité") return { "global_success": global_success, "successful_validations": successful_validations, "total_validations": total_validations, "total_errors": total_errors, "total_warnings": total_warnings, "results": [ { "name": r.name, "success": r.success, "errors": r.errors, "warnings": r.warnings, "details": r.details } for r in self.results ] } def main(): """Fonction principale""" validator = InterfacePropertiesValidator() results = validator.run_validation() # Sauvegarder les résultats results_file = PROJECT_ROOT / "validation_checkpoint_interface_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["global_success"] else 1) if __name__ == "__main__": main()