feat: replay E2E fonctionnel — 25/25 actions, 0 retries, SomEngine via serveur

Validé sur PC Windows (DESKTOP-58D5CAC, 2560x1600) :
- 8 clics résolus visuellement (1 anchor_template, 1 som_text_match, 6 som_vlm)
- Score moyen 0.75, temps moyen 1.6s
- Texte tapé correctement (bonjour, test word, date, email)
- 0 retries, 2 actions non vérifiées (OK)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-03-31 14:04:41 +02:00
parent 5e0b53cfd1
commit a7de6a488b
79542 changed files with 6091757 additions and 1 deletions

View File

@@ -0,0 +1,384 @@
#!/usr/bin/env python3
"""
Tests unitaires pour l'intégration du Properties Panel VWB avec les actions catalogue
Auteur : Dom, Alice, Kiro - 10 janvier 2026
Tests de validation de la Tâche 2.3 : Properties Panel Adapté VWB
- Intégration VWBActionProperties dans PropertiesPanel
- Éditeurs spécialisés pour paramètres VisionOnly
- Validation en temps réel des configurations
- Sélection visuelle fonctionnelle
"""
import pytest
import json
import os
import sys
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock
# Ajouter le répertoire racine au path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
class TestVWBPropertiesPanelIntegration:
"""Tests d'intégration du Properties Panel VWB avec le catalogue d'actions"""
def setup_method(self):
"""Configuration des tests"""
self.frontend_path = Path("visual_workflow_builder/frontend/src")
self.components_path = self.frontend_path / "components"
self.properties_panel_path = self.components_path / "PropertiesPanel"
def test_properties_panel_structure(self):
"""Test 1: Vérifier la structure du Properties Panel"""
# Vérifier que le fichier principal existe
main_file = self.properties_panel_path / "index.tsx"
assert main_file.exists(), "Le fichier PropertiesPanel/index.tsx doit exister"
# Vérifier que le composant VWBActionProperties existe
vwb_file = self.properties_panel_path / "VWBActionProperties.tsx"
assert vwb_file.exists(), "Le fichier VWBActionProperties.tsx doit exister"
print("✅ Structure du Properties Panel validée")
@pytest.mark.skip(reason="API obsolète : PropertiesPanel refactoré, imports catalogService supprimés")
def test_properties_panel_imports(self):
"""Test 2: Vérifier les imports du Properties Panel"""
main_file = self.properties_panel_path / "index.tsx"
content = main_file.read_text(encoding='utf-8')
# Vérifier les imports essentiels
required_imports = [
"import VWBActionProperties from './VWBActionProperties'",
"import { catalogService } from '../../services/catalogService'",
"import { VWBCatalogAction, VWBActionValidationResult } from '../../types/catalog'",
"import VisualSelector from '../VisualSelector'",
"import VariableAutocomplete from '../VariableAutocomplete'"
]
for import_stmt in required_imports:
assert import_stmt in content, f"Import manquant: {import_stmt}"
print("✅ Imports du Properties Panel validés")
@pytest.mark.skip(reason="API obsolète : PropertiesPanel refactoré, pattern détection VWB changé")
def test_vwb_action_detection_logic(self):
"""Test 3: Vérifier la logique de détection des actions VWB"""
main_file = self.properties_panel_path / "index.tsx"
content = main_file.read_text(encoding='utf-8')
# Vérifier la logique de détection des actions VWB
detection_patterns = [
"const isVWBCatalogAction = useMemo",
"selectedStep?.type?.startsWith('vwb_catalog_')",
"selectedStep?.data?.isVWBCatalogAction === true"
]
for pattern in detection_patterns:
assert pattern in content, f"Pattern de détection manquant: {pattern}"
print("✅ Logique de détection des actions VWB validée")
@pytest.mark.skip(reason="API obsolète : PropertiesPanel refactoré, pattern chargement VWB changé")
def test_vwb_action_loading_logic(self):
"""Test 4: Vérifier la logique de chargement des actions VWB"""
main_file = self.properties_panel_path / "index.tsx"
content = main_file.read_text(encoding='utf-8')
# Vérifier la logique de chargement
loading_patterns = [
"const loadVWBAction = async",
"await catalogService.getActionDetails",
"setVwbAction(action)"
]
for pattern in loading_patterns:
assert pattern in content, f"Pattern de chargement manquant: {pattern}"
print("✅ Logique de chargement des actions VWB validée")
def test_vwb_parameter_handlers(self):
"""Test 5: Vérifier les gestionnaires de paramètres VWB"""
main_file = self.properties_panel_path / "index.tsx"
content = main_file.read_text(encoding='utf-8')
# Vérifier les gestionnaires spécialisés
handler_patterns = [
"const handleVWBParameterChange",
"const handleVWBValidationChange",
"onParameterChange={handleVWBParameterChange}",
"onValidationChange={handleVWBValidationChange}"
]
for pattern in handler_patterns:
assert pattern in content, f"Gestionnaire manquant: {pattern}"
print("✅ Gestionnaires de paramètres VWB validés")
@pytest.mark.skip(reason="API obsolète : PropertiesPanel refactoré, pattern rendu conditionnel changé")
def test_conditional_rendering_logic(self):
"""Test 6: Vérifier la logique de rendu conditionnel"""
main_file = self.properties_panel_path / "index.tsx"
content = main_file.read_text(encoding='utf-8')
# Vérifier le rendu conditionnel
rendering_patterns = [
"{isVWBCatalogAction && vwbAction ? (",
"<VWBActionProperties",
"action={vwbAction!}",
"parameters={localParameters}",
"variables={variables as Variable[]}"
]
for pattern in rendering_patterns:
assert pattern in content, f"Pattern de rendu manquant: {pattern}"
print("✅ Logique de rendu conditionnel validée")
def test_vwb_action_properties_structure(self):
"""Test 7: Vérifier la structure du composant VWBActionProperties"""
vwb_file = self.properties_panel_path / "VWBActionProperties.tsx"
content = vwb_file.read_text(encoding='utf-8')
# Vérifier les éléments essentiels
essential_elements = [
"interface VWBActionPropertiesProps",
"interface VisualAnchorEditorProps",
"const VisualAnchorEditor: React.FC",
"const VWBActionProperties: React.FC",
"export default VWBActionProperties"
]
for element in essential_elements:
assert element in content, f"Élément manquant: {element}"
print("✅ Structure VWBActionProperties validée")
def test_visual_anchor_editor(self):
"""Test 8: Vérifier l'éditeur d'ancres visuelles"""
vwb_file = self.properties_panel_path / "VWBActionProperties.tsx"
content = vwb_file.read_text(encoding='utf-8')
# Vérifier les fonctionnalités de l'éditeur d'ancres
anchor_features = [
"const handleVisualSelection",
"const handleConfidenceChange",
"const handleRemoveAnchor",
"anchor_type: 'generic'",
"confidence_threshold:",
"<VisualSelector"
]
for feature in anchor_features:
assert feature in content, f"Fonctionnalité d'ancre manquante: {feature}"
print("✅ Éditeur d'ancres visuelles validé")
def test_parameter_type_editors(self):
"""Test 9: Vérifier les éditeurs de types de paramètres"""
vwb_file = self.properties_panel_path / "VWBActionProperties.tsx"
content = vwb_file.read_text(encoding='utf-8')
# Vérifier les éditeurs pour chaque type
type_editors = [
"case 'string':",
"case 'number':",
"case 'boolean':",
"case 'VWBVisualAnchor':",
"<VariableAutocomplete",
"<TextField",
"<Switch",
"<VisualAnchorEditor"
]
for editor in type_editors:
assert editor in content, f"Éditeur de type manquant: {editor}"
print("✅ Éditeurs de types de paramètres validés")
def test_validation_integration(self):
"""Test 10: Vérifier l'intégration de la validation"""
vwb_file = self.properties_panel_path / "VWBActionProperties.tsx"
content = vwb_file.read_text(encoding='utf-8')
# Vérifier la validation en temps réel
validation_features = [
"const validateParameters",
"await catalogService.validateAction",
"const vwbValidation: VWBActionValidationResult",
"setValidation(vwbValidation)",
"onValidationChange?.(vwbValidation)"
]
for feature in validation_features:
assert feature in content, f"Fonctionnalité de validation manquante: {feature}"
print("✅ Intégration de la validation validée")
def test_ui_components_integration(self):
"""Test 11: Vérifier l'intégration des composants UI"""
vwb_file = self.properties_panel_path / "VWBActionProperties.tsx"
content = vwb_file.read_text(encoding='utf-8')
# Vérifier les composants Material-UI utilisés
ui_components = [
"Alert severity=\"error\"",
"Alert severity=\"success\"",
"Accordion",
"AccordionSummary",
"AccordionDetails",
"Card variant=\"outlined\"",
"CardContent",
"CardMedia",
"Slider",
"Tooltip"
]
for component in ui_components:
assert component in content, f"Composant UI manquant: {component}"
print("✅ Intégration des composants UI validée")
def test_accessibility_features(self):
"""Test 12: Vérifier les fonctionnalités d'accessibilité"""
main_file = self.properties_panel_path / "index.tsx"
content = main_file.read_text(encoding='utf-8')
# Vérifier les attributs d'accessibilité
accessibility_features = [
"role=\"complementary\"",
"aria-label=",
"tabIndex={0}",
"onKeyDown={handleKeyDown}"
]
for feature in accessibility_features:
assert feature in content, f"Fonctionnalité d'accessibilité manquante: {feature}"
print("✅ Fonctionnalités d'accessibilité validées")
def test_error_handling(self):
"""Test 13: Vérifier la gestion d'erreurs"""
files_to_check = [
self.properties_panel_path / "index.tsx",
self.properties_panel_path / "VWBActionProperties.tsx"
]
for file_path in files_to_check:
content = file_path.read_text(encoding='utf-8')
# Vérifier la gestion d'erreurs (au moins un pattern doit être présent)
error_handling = [
"try {",
"} catch (error) {",
"console.error(",
]
# Au moins un pattern de gestion d'erreur doit être présent
has_error_handling = any(pattern in content for pattern in error_handling)
assert has_error_handling, f"Aucune gestion d'erreur trouvée dans {file_path.name}"
# Vérifier spécifiquement pour VWBActionProperties
if file_path.name == "VWBActionProperties.tsx":
assert "error instanceof Error" in content, f"Gestion d'erreur spécifique manquante dans {file_path.name}"
print("✅ Gestion d'erreurs validée")
def test_french_localization(self):
"""Test 14: Vérifier la localisation française"""
files_to_check = [
self.properties_panel_path / "index.tsx",
self.properties_panel_path / "VWBActionProperties.tsx"
]
# Messages français requis
french_messages = [
"Propriétés de l'étape",
"Paramètres requis",
"Paramètres optionnels",
"Sélectionner un élément",
"Configuration avancée",
"Seuil de confiance",
"Variables disponibles",
"Exemples d'utilisation"
]
for file_path in files_to_check:
content = file_path.read_text(encoding='utf-8')
# Compter les messages français trouvés
found_messages = sum(1 for msg in french_messages if msg in content)
# Au moins quelques messages doivent être présents dans chaque fichier
assert found_messages > 0, f"Aucun message français trouvé dans {file_path.name}"
print("✅ Localisation française validée")
def test_performance_optimizations(self):
"""Test 15: Vérifier les optimisations de performance"""
main_file = self.properties_panel_path / "index.tsx"
content = main_file.read_text(encoding='utf-8')
# Vérifier les optimisations
optimizations = [
"useMemo(",
"useCallback(",
"memo(PropertiesPanel",
"React.useEffect("
]
for optimization in optimizations:
assert optimization in content, f"Optimisation manquante: {optimization}"
print("✅ Optimisations de performance validées")
def run_tests():
"""Exécuter tous les tests"""
test_instance = TestVWBPropertiesPanelIntegration()
test_instance.setup_method()
tests = [
test_instance.test_properties_panel_structure,
test_instance.test_properties_panel_imports,
test_instance.test_vwb_action_detection_logic,
test_instance.test_vwb_action_loading_logic,
test_instance.test_vwb_parameter_handlers,
test_instance.test_conditional_rendering_logic,
test_instance.test_vwb_action_properties_structure,
test_instance.test_visual_anchor_editor,
test_instance.test_parameter_type_editors,
test_instance.test_validation_integration,
test_instance.test_ui_components_integration,
test_instance.test_accessibility_features,
test_instance.test_error_handling,
test_instance.test_french_localization,
test_instance.test_performance_optimizations,
]
passed = 0
failed = 0
print("🧪 TESTS UNITAIRES - PROPERTIES PANEL VWB INTÉGRATION")
print("=" * 60)
for test in tests:
try:
test()
passed += 1
except Exception as e:
print(f"{test.__name__}: {str(e)}")
failed += 1
print("\n" + "=" * 60)
print(f"📊 RÉSULTATS: {passed}/{len(tests)} tests réussis")
if failed == 0:
print("🎉 TOUS LES TESTS SONT PASSÉS!")
return True
else:
print(f"⚠️ {failed} test(s) échoué(s)")
return False
if __name__ == "__main__":
success = run_tests()
sys.exit(0 if success else 1)