- Frontend v4 accessible sur réseau local (192.168.1.40) - Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard) - Ollama GPU fonctionnel - Self-healing interactif - Dashboard confiance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
483 lines
19 KiB
Python
483 lines
19 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test de diagnostic pour la documentation interactive
|
|
Vérifie si le service de documentation fonctionne correctement
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import json
|
|
import requests
|
|
import time
|
|
from pathlib import Path
|
|
|
|
# Ajouter le répertoire backend au path
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'backend'))
|
|
|
|
def test_backend_running():
|
|
"""Test si le backend est accessible et retourne des données valides"""
|
|
try:
|
|
# Test endpoint principal
|
|
response = requests.get('http://localhost:5001/api/workflows', timeout=5)
|
|
print(f"✓ Backend accessible - Status: {response.status_code}")
|
|
|
|
# Vérifier que la réponse est du JSON valide
|
|
if response.status_code == 200:
|
|
try:
|
|
data = response.json()
|
|
print(f"✓ Réponse JSON valide: {type(data)}")
|
|
except json.JSONDecodeError:
|
|
print("⚠ Réponse non-JSON du backend")
|
|
return False
|
|
|
|
# Test endpoint spécifique à la documentation si disponible
|
|
try:
|
|
doc_response = requests.get('http://localhost:5001/api/documentation/tools', timeout=3)
|
|
if doc_response.status_code == 200:
|
|
print("✓ Endpoint documentation accessible")
|
|
else:
|
|
print(f"⚠ Endpoint documentation: {doc_response.status_code}")
|
|
except requests.exceptions.RequestException:
|
|
print("⚠ Endpoint documentation non disponible (optionnel)")
|
|
|
|
return True
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"✗ Backend non accessible: {e}")
|
|
return False
|
|
|
|
def test_documentation_data():
|
|
"""Test si les données de documentation sont correctes"""
|
|
try:
|
|
# Vérifier que le fichier de documentation existe
|
|
doc_file = Path(__file__).parent / 'frontend' / 'src' / 'data' / 'toolDocumentation.ts'
|
|
if not doc_file.exists():
|
|
print(f"✗ Fichier de documentation manquant: {doc_file}")
|
|
return False
|
|
|
|
print(f"✓ Fichier de documentation trouvé: {doc_file}")
|
|
|
|
# Lire le contenu
|
|
content = doc_file.read_text()
|
|
|
|
# Vérifier que les exports sont présents
|
|
if 'export const TOOLS_DOCUMENTATION' in content:
|
|
print("✓ TOOLS_DOCUMENTATION exporté")
|
|
else:
|
|
print("✗ TOOLS_DOCUMENTATION manquant")
|
|
return False
|
|
|
|
if 'export const GENERAL_DOCUMENTATION' in content:
|
|
print("✓ GENERAL_DOCUMENTATION exporté")
|
|
else:
|
|
print("✗ GENERAL_DOCUMENTATION manquant")
|
|
return False
|
|
|
|
# Vérifier quelques outils de base avec validation plus approfondie
|
|
tools_to_check = [
|
|
('click', 'Cliquer sur un élément'),
|
|
('type', 'Saisir du texte'),
|
|
('wait', 'Attendre'),
|
|
('navigate', 'Naviguer')
|
|
]
|
|
|
|
for tool, expected_desc in tools_to_check:
|
|
if f"'{tool}':" in content or f'"{tool}":' in content or f'{tool}:' in content:
|
|
print(f"✓ Outil {tool} trouvé dans la documentation")
|
|
# Vérifier qu'il y a une description substantielle
|
|
tool_section_start = max(
|
|
content.find(f'"{tool}":'),
|
|
content.find(f"'{tool}':"),
|
|
content.find(f'{tool}:')
|
|
)
|
|
if tool_section_start > 0:
|
|
tool_section = content[tool_section_start:tool_section_start + 500]
|
|
if 'description' in tool_section:
|
|
desc_start = tool_section.find('description')
|
|
if desc_start > 0:
|
|
desc_content = tool_section[desc_start:desc_start + 200]
|
|
if len(desc_content.split(':')[1][:100].strip()) > 10:
|
|
print(f" ✓ Description substantielle trouvée pour {tool}")
|
|
else:
|
|
print(f" ⚠ Description courte pour {tool}")
|
|
else:
|
|
print(f" ⚠ Pas de champ description pour {tool}")
|
|
else:
|
|
print(f"✗ Outil {tool} manquant dans la documentation")
|
|
return False
|
|
|
|
# Vérifier la syntaxe TypeScript basique
|
|
brace_balance = content.count('{') - content.count('}')
|
|
if brace_balance != 0:
|
|
print(f"✗ Syntaxe TypeScript invalide (déséquilibre d'accolades: {brace_balance})")
|
|
return False
|
|
|
|
# Compter approximativement le nombre d'outils documentés
|
|
tool_entries = content.count('description:') + content.count('"description"')
|
|
if tool_entries >= 4:
|
|
print(f"✓ {tool_entries} outils documentés détectés")
|
|
else:
|
|
print(f"⚠ Seulement {tool_entries} outils documentés détectés")
|
|
|
|
print("✓ Syntaxe TypeScript semble valide")
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ Erreur lors de la vérification des données: {e}")
|
|
return False
|
|
|
|
def test_documentation_service_integration():
|
|
"""Test l'intégration réelle du service de documentation"""
|
|
try:
|
|
# Importer et tester le service de documentation réel
|
|
service_file = Path(__file__).parent / 'frontend' / 'src' / 'services' / 'DocumentationService.ts'
|
|
if not service_file.exists():
|
|
print("✗ DocumentationService.ts manquant")
|
|
return False
|
|
|
|
service_content = service_file.read_text()
|
|
|
|
# Vérifier les méthodes essentielles
|
|
required_methods = [
|
|
'getToolDocumentation',
|
|
'getGeneralDocumentation',
|
|
'preloadDocumentation'
|
|
]
|
|
|
|
for method in required_methods:
|
|
if method in service_content:
|
|
print(f"✓ Méthode {method} trouvée")
|
|
else:
|
|
print(f"✗ Méthode {method} manquante")
|
|
return False
|
|
|
|
# Vérifier l'import des données
|
|
if 'toolDocumentation' in service_content:
|
|
print("✓ Import des données de documentation détecté")
|
|
else:
|
|
print("✗ Import des données manquant")
|
|
return False
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ Erreur lors du test du service: {e}")
|
|
return False
|
|
|
|
|
|
def test_frontend_files():
|
|
"""Test si les fichiers frontend de documentation existent et sont valides"""
|
|
frontend_dir = Path(__file__).parent / 'frontend' / 'src'
|
|
|
|
files_to_check = [
|
|
('services/DocumentationService.ts', ['class DocumentationService', 'getToolDocumentation', 'export']),
|
|
('components/DocumentationTab/index.tsx', ['DocumentationTab', 'React', 'export default']),
|
|
('components/DocumentationPopup/index.tsx', ['DocumentationPopup', 'React', 'export default']),
|
|
('types/documentation.ts', ['interface', 'export', 'ToolDocumentation'])
|
|
]
|
|
|
|
all_valid = True
|
|
for file_path, required_content in files_to_check:
|
|
full_path = frontend_dir / file_path
|
|
if full_path.exists():
|
|
print(f"✓ {file_path} existe")
|
|
|
|
# Vérifier le contenu réel du fichier
|
|
try:
|
|
content = full_path.read_text()
|
|
missing_content = []
|
|
for required in required_content:
|
|
if required not in content:
|
|
missing_content.append(required)
|
|
|
|
if missing_content:
|
|
print(f" ⚠ Contenu manquant dans {file_path}: {missing_content}")
|
|
all_valid = False
|
|
else:
|
|
print(f" ✓ Contenu valide pour {file_path}")
|
|
|
|
# Vérifier la taille du fichier (doit être substantiel)
|
|
if len(content) < 100:
|
|
print(f" ⚠ Fichier {file_path} semble trop petit ({len(content)} caractères)")
|
|
all_valid = False
|
|
|
|
except Exception as e:
|
|
print(f" ✗ Erreur lecture {file_path}: {e}")
|
|
all_valid = False
|
|
else:
|
|
print(f"✗ {file_path} manquant")
|
|
all_valid = False
|
|
|
|
return all_valid
|
|
|
|
def test_app_integration():
|
|
"""Test si App.tsx intègre correctement la documentation avec validation du code réel"""
|
|
try:
|
|
app_file = Path(__file__).parent / 'frontend' / 'src' / 'App.tsx'
|
|
if not app_file.exists():
|
|
print("✗ App.tsx manquant")
|
|
return False
|
|
|
|
content = app_file.read_text()
|
|
|
|
# Vérifier l'import du service de documentation
|
|
import_patterns = [
|
|
'documentationService',
|
|
'DocumentationService',
|
|
'from.*DocumentationService'
|
|
]
|
|
|
|
import_found = any(pattern.replace('.*', '') in content for pattern in import_patterns)
|
|
if import_found:
|
|
print("✓ DocumentationService importé dans App.tsx")
|
|
else:
|
|
print("✗ DocumentationService non importé dans App.tsx")
|
|
return False
|
|
|
|
# Vérifier l'initialisation ou utilisation
|
|
usage_patterns = [
|
|
'preloadDocumentation',
|
|
'documentationService',
|
|
'useEffect',
|
|
'Documentation'
|
|
]
|
|
|
|
usage_found = sum(1 for pattern in usage_patterns if pattern in content)
|
|
if usage_found >= 2:
|
|
print(f"✓ Utilisation de la documentation détectée ({usage_found} patterns)")
|
|
else:
|
|
print(f"⚠ Utilisation limitée de la documentation ({usage_found} patterns)")
|
|
|
|
# Vérifier que le fichier est un composant React valide
|
|
react_indicators = ['import React', 'export default', 'function App', 'const App']
|
|
if any(indicator in content for indicator in react_indicators):
|
|
print("✓ App.tsx est un composant React valide")
|
|
else:
|
|
print("✗ App.tsx ne semble pas être un composant React valide")
|
|
return False
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ Erreur lors de la vérification d'App.tsx: {e}")
|
|
return False
|
|
|
|
def test_properties_panel_integration():
|
|
"""Test si PropertiesPanel intègre l'onglet Documentation avec validation complète"""
|
|
try:
|
|
props_file = Path(__file__).parent / 'frontend' / 'src' / 'components' / 'PropertiesPanel' / 'index.tsx'
|
|
if not props_file.exists():
|
|
print("✗ PropertiesPanel/index.tsx manquant")
|
|
return False
|
|
|
|
content = props_file.read_text()
|
|
|
|
# Vérifier l'import de DocumentationTab
|
|
if 'DocumentationTab' in content:
|
|
print("✓ DocumentationTab importé dans PropertiesPanel")
|
|
else:
|
|
print("✗ DocumentationTab non importé dans PropertiesPanel")
|
|
return False
|
|
|
|
# Vérifier la structure des onglets avec validation plus robuste
|
|
tab_indicators = ['Tab', 'TabPanel', 'Tabs', 'Documentation']
|
|
tab_score = sum(1 for indicator in tab_indicators if indicator in content)
|
|
|
|
if tab_score >= 3:
|
|
print(f"✓ Structure d'onglets détectée (score: {tab_score}/4)")
|
|
else:
|
|
print(f"⚠ Structure d'onglets incomplète (score: {tab_score}/4)")
|
|
|
|
# Vérifier le rendu conditionnel ou la gestion d'état
|
|
state_patterns = [
|
|
'activeTab',
|
|
'selectedTab',
|
|
'useState',
|
|
'tabIndex',
|
|
'value='
|
|
]
|
|
|
|
state_found = any(pattern in content for pattern in state_patterns)
|
|
if state_found:
|
|
print("✓ Gestion d'état des onglets détectée")
|
|
else:
|
|
print("⚠ Gestion d'état des onglets non détectée")
|
|
|
|
# Vérifier que DocumentationTab est effectivement rendu
|
|
render_patterns = [
|
|
'<DocumentationTab',
|
|
'DocumentationTab',
|
|
'documentation'
|
|
]
|
|
|
|
render_found = sum(1 for pattern in render_patterns if pattern in content)
|
|
if render_found >= 2:
|
|
print("✓ Rendu de DocumentationTab confirmé")
|
|
else:
|
|
print("⚠ Rendu de DocumentationTab incertain")
|
|
|
|
# Vérifier que c'est un composant React valide
|
|
if 'export default' in content and ('function' in content or 'const' in content):
|
|
print("✓ PropertiesPanel est un composant React valide")
|
|
return True
|
|
else:
|
|
print("✗ PropertiesPanel ne semble pas être un composant React valide")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"✗ Erreur lors de la vérification de PropertiesPanel: {e}")
|
|
return False
|
|
|
|
def test_documentation_performance():
|
|
"""Test les performances de chargement de la documentation"""
|
|
try:
|
|
import time
|
|
|
|
print("\n--- Test de performance ---")
|
|
|
|
# Mesurer le temps de lecture des données
|
|
start_time = time.time()
|
|
|
|
doc_file = Path(__file__).parent / 'frontend' / 'src' / 'data' / 'toolDocumentation.ts'
|
|
if doc_file.exists():
|
|
content = doc_file.read_text()
|
|
file_size = len(content)
|
|
|
|
read_time = time.time() - start_time
|
|
|
|
print(f"✓ Fichier de documentation lu en {read_time:.3f}s")
|
|
print(f"✓ Taille du fichier: {file_size} caractères ({file_size/1024:.1f} KB)")
|
|
|
|
if read_time > 1.0:
|
|
print("⚠ Temps de lecture élevé (>1s)")
|
|
return False
|
|
|
|
if file_size > 100000: # 100KB
|
|
print("⚠ Fichier de documentation très volumineux (>100KB)")
|
|
|
|
# Test de parsing basique
|
|
start_parse = time.time()
|
|
tool_count = content.count('description:')
|
|
parse_time = time.time() - start_parse
|
|
|
|
print(f"✓ Parsing basique en {parse_time:.3f}s ({tool_count} outils détectés)")
|
|
|
|
return True
|
|
else:
|
|
print("✗ Fichier de documentation non trouvé")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"✗ Erreur dans le test de performance: {e}")
|
|
return False
|
|
|
|
|
|
def test_end_to_end_documentation_flow():
|
|
"""Test le flux complet de documentation de bout en bout"""
|
|
try:
|
|
print("\n--- Test du flux complet de documentation ---")
|
|
|
|
# 1. Vérifier que les données existent et sont parsables
|
|
doc_file = Path(__file__).parent / 'frontend' / 'src' / 'data' / 'toolDocumentation.ts'
|
|
if not doc_file.exists():
|
|
print("✗ Données de documentation manquantes")
|
|
return False
|
|
|
|
content = doc_file.read_text()
|
|
|
|
# 2. Extraire un outil spécifique pour test
|
|
test_tools = ['click', 'type', 'wait']
|
|
found_tool = None
|
|
|
|
for tool in test_tools:
|
|
if f'"{tool}":' in content or f"'{tool}':" in content:
|
|
found_tool = tool
|
|
break
|
|
|
|
if not found_tool:
|
|
print("✗ Aucun outil de test trouvé dans les données")
|
|
return False
|
|
|
|
print(f"✓ Outil de test trouvé: {found_tool}")
|
|
|
|
# 3. Vérifier que le service peut être importé (simulation d'import)
|
|
service_file = Path(__file__).parent / 'frontend' / 'src' / 'services' / 'DocumentationService.ts'
|
|
if service_file.exists():
|
|
service_content = service_file.read_text()
|
|
if 'getToolDocumentation' in service_content and 'toolDocumentation' in service_content:
|
|
print("✓ Service de documentation correctement configuré")
|
|
else:
|
|
print("⚠ Service de documentation incomplet")
|
|
return False
|
|
|
|
# 4. Vérifier que les composants peuvent consommer les données
|
|
tab_file = Path(__file__).parent / 'frontend' / 'src' / 'components' / 'DocumentationTab' / 'index.tsx'
|
|
if tab_file.exists():
|
|
tab_content = tab_file.read_text()
|
|
if 'documentationService' in tab_content or 'DocumentationService' in tab_content:
|
|
print("✓ DocumentationTab connecté au service")
|
|
else:
|
|
print("⚠ DocumentationTab non connecté au service")
|
|
|
|
# 5. Test de cohérence des types
|
|
types_file = Path(__file__).parent / 'frontend' / 'src' / 'types' / 'documentation.ts'
|
|
if types_file.exists():
|
|
types_content = types_file.read_text()
|
|
if 'ToolDocumentation' in types_content and 'interface' in types_content:
|
|
print("✓ Types de documentation définis")
|
|
else:
|
|
print("⚠ Types de documentation incomplets")
|
|
|
|
print("✓ Flux de documentation validé de bout en bout")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ Erreur dans le test de flux complet: {e}")
|
|
return False
|
|
|
|
|
|
def main():
|
|
"""Fonction principale de diagnostic"""
|
|
print("=== DIAGNOSTIC DE LA DOCUMENTATION INTERACTIVE ===\n")
|
|
|
|
tests = [
|
|
("Données de documentation", test_documentation_data),
|
|
("Service de documentation", test_documentation_service_integration),
|
|
("Fichiers frontend", test_frontend_files),
|
|
("Intégration App.tsx", test_app_integration),
|
|
("Intégration PropertiesPanel", test_properties_panel_integration),
|
|
("Performance documentation", test_documentation_performance),
|
|
("Flux complet de documentation", test_end_to_end_documentation_flow),
|
|
("Backend accessible", test_backend_running),
|
|
]
|
|
|
|
results = []
|
|
for test_name, test_func in tests:
|
|
print(f"\n--- {test_name} ---")
|
|
result = test_func()
|
|
results.append((test_name, result))
|
|
|
|
print("\n=== RÉSUMÉ ===")
|
|
all_passed = True
|
|
for test_name, result in results:
|
|
status = "✓ PASS" if result else "✗ FAIL"
|
|
print(f"{status} {test_name}")
|
|
if not result:
|
|
all_passed = False
|
|
|
|
if all_passed:
|
|
print("\n🎉 Tous les tests sont passés ! La documentation devrait fonctionner.")
|
|
print("\nPour tester l'interface:")
|
|
print("1. Démarrez le backend: cd backend && python app.py")
|
|
print("2. Démarrez le frontend: cd frontend && npm start")
|
|
print("3. Ouvrez http://localhost:3000")
|
|
print("4. Ajoutez un nœud et cliquez dessus")
|
|
print("5. Cliquez sur l'onglet 'Documentation' dans le panneau de propriétés")
|
|
else:
|
|
print("\n❌ Certains tests ont échoué. Vérifiez les erreurs ci-dessus.")
|
|
|
|
return all_passed
|
|
|
|
if __name__ == "__main__":
|
|
success = main()
|
|
sys.exit(0 if success else 1) |