Files
rpa_vision_v3/scripts/test_proprietes_etapes_debug_12jan2026.py
Dom a27b74cf22 v1.0 - Version stable: multi-PC, détection UI-DETR-1, 3 modes exécution
- 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>
2026-01-29 11:23:51 +01:00

726 lines
24 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Script de Test Debug - Propriétés d'Étapes VWB
Auteur : Dom, Alice, Kiro - 12 janvier 2026
Ce script teste en temps réel le problème des propriétés d'étapes vides
en créant un composant de test qui affiche les informations de débogage.
"""
import os
import sys
from pathlib import Path
def create_debug_component():
"""Crée un composant de test pour déboguer les propriétés d'étapes."""
project_root = Path(__file__).parent.parent
frontend_path = project_root / "visual_workflow_builder" / "frontend"
# Créer le composant de test
test_component_path = frontend_path / "src" / "components" / "PropertiesDebugTest.tsx"
test_component_content = '''/**
* Composant de Test Debug - Propriétés d'Étapes
* Auteur : Dom, Alice, Kiro - 12 janvier 2026
*
* Ce composant teste et affiche les informations de débogage pour
* diagnostiquer le problème des propriétés d'étapes vides.
*/
import React, { useState, useCallback, useMemo } from 'react';
import {
Box,
Typography,
Button,
Card,
CardContent,
Alert,
Accordion,
AccordionSummary,
AccordionDetails,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper,
Chip,
} from '@mui/material';
import {
ExpandMore as ExpandMoreIcon,
BugReport as BugIcon,
CheckCircle as CheckIcon,
Error as ErrorIcon,
} from '@mui/icons-material';
// Import des types
import { Step, StepType, StepExecutionState } from '../types';
// Import des hooks VWB
import { useVWBStepIntegration, useIsVWBStep, useVWBActionId } from '../hooks/useVWBStepIntegration';
// Configuration des paramètres (copie de PropertiesPanel)
interface ParameterConfig {
name: string;
label: string;
type: 'text' | 'number' | 'boolean' | 'select' | 'visual';
required?: boolean;
description?: string;
supportVariables?: boolean;
options?: { value: string; label: string }[];
defaultValue?: any;
min?: number;
max?: number;
}
const stepParametersConfig: Record<StepType, ParameterConfig[]> = {
click: [
{
name: 'target',
label: 'Élément cible',
type: 'visual',
required: true,
description: 'Sélectionner l\\'élément à cliquer',
},
{
name: 'clickType',
label: 'Type de clic',
type: 'select',
options: [
{ value: 'left', label: 'Clic gauche' },
{ value: 'right', label: 'Clic droit' },
{ value: 'double', label: 'Double-clic' },
],
defaultValue: 'left',
},
],
type: [
{
name: 'target',
label: 'Champ de saisie',
type: 'visual',
required: true,
description: 'Sélectionner le champ où saisir le texte',
},
{
name: 'text',
label: 'Texte à saisir',
type: 'text',
required: true,
supportVariables: true,
},
{
name: 'clearFirst',
label: 'Vider le champ d\\'abord',
type: 'boolean',
defaultValue: true,
},
],
wait: [
{
name: 'duration',
label: 'Durée (secondes)',
type: 'number',
required: true,
min: 0.1,
max: 60,
defaultValue: 1,
},
],
condition: [
{
name: 'condition',
label: 'Condition',
type: 'text',
required: true,
supportVariables: true,
description: 'Expression conditionnelle à évaluer',
},
],
extract: [
{
name: 'target',
label: 'Élément source',
type: 'visual',
required: true,
description: 'Sélectionner l\\'élément dont extraire les données',
},
{
name: 'attribute',
label: 'Attribut à extraire',
type: 'select',
options: [
{ value: 'text', label: 'Texte' },
{ value: 'value', label: 'Valeur' },
{ value: 'href', label: 'Lien (href)' },
{ value: 'src', label: 'Source (src)' },
],
defaultValue: 'text',
},
],
scroll: [
{
name: 'direction',
label: 'Direction',
type: 'select',
options: [
{ value: 'up', label: 'Vers le haut' },
{ value: 'down', label: 'Vers le bas' },
{ value: 'left', label: 'Vers la gauche' },
{ value: 'right', label: 'Vers la droite' },
],
defaultValue: 'down',
},
{
name: 'amount',
label: 'Quantité (pixels)',
type: 'number',
defaultValue: 300,
min: 1,
},
],
navigate: [
{
name: 'url',
label: 'URL de destination',
type: 'text',
required: true,
supportVariables: true,
},
],
screenshot: [
{
name: 'filename',
label: 'Nom du fichier',
type: 'text',
supportVariables: true,
description: 'Nom du fichier de capture (optionnel)',
},
],
};
/**
* Composant de test pour déboguer les propriétés d'étapes
*/
const PropertiesDebugTest: React.FC = () => {
const [selectedStepType, setSelectedStepType] = useState<StepType>('click');
const [testResults, setTestResults] = useState<any[]>([]);
// Hooks VWB
const { methods: vwbMethods } = useVWBStepIntegration();
// Créer une étape de test
const createTestStep = useCallback((stepType: StepType): Step => {
return {
id: `test_step_${Date.now()}`,
type: stepType,
name: `Test ${stepType}`,
position: { x: 100, y: 100 },
data: {
label: `Test ${stepType}`,
stepType: stepType,
parameters: {},
},
executionState: StepExecutionState.IDLE,
validationErrors: [],
};
}, []);
// Tester la résolution des paramètres
const testParameterResolution = useCallback((stepType: StepType) => {
console.log(`🧪 Test de résolution pour le type: ${stepType}`);
const testStep = createTestStep(stepType);
// Test 1: Configuration directe
const directConfig = stepParametersConfig[stepType];
// Test 2: Fonction getParameterConfig simulée
const getParameterConfig = (step: Step): ParameterConfig[] => {
if (!step) return [];
console.log(`🔍 Recherche config pour type: "${step.type}"`);
console.log(`🔍 Clés disponibles:`, Object.keys(stepParametersConfig));
console.log(`🔍 Type exact match:`, stepParametersConfig[step.type] !== undefined);
return stepParametersConfig[step.type] || [];
};
const resolvedConfig = getParameterConfig(testStep);
// Test 3: Hooks VWB
const isVWBStep = useIsVWBStep(testStep);
const vwbActionId = useVWBActionId(testStep);
const result = {
stepType,
testStep,
directConfig: directConfig || null,
directConfigLength: directConfig ? directConfig.length : 0,
resolvedConfig,
resolvedConfigLength: resolvedConfig.length,
isVWBStep,
vwbActionId,
configExists: stepParametersConfig[stepType] !== undefined,
timestamp: new Date().toISOString(),
};
console.log(`✅ Résultat test ${stepType}:`, result);
setTestResults(prev => [...prev, result]);
return result;
}, [createTestStep]);
// Tester tous les types d'étapes
const testAllStepTypes = useCallback(() => {
console.log('🚀 Test de tous les types d\\'étapes');
setTestResults([]);
const allTypes: StepType[] = ['click', 'type', 'wait', 'condition', 'extract', 'scroll', 'navigate', 'screenshot'];
allTypes.forEach(stepType => {
setTimeout(() => testParameterResolution(stepType), 100);
});
}, [testParameterResolution]);
// Analyser les résultats
const analysisResults = useMemo(() => {
if (testResults.length === 0) return null;
const totalTests = testResults.length;
const successfulResolutions = testResults.filter(r => r.resolvedConfigLength > 0).length;
const failedResolutions = testResults.filter(r => r.resolvedConfigLength === 0).length;
const vwbSteps = testResults.filter(r => r.isVWBStep).length;
return {
totalTests,
successfulResolutions,
failedResolutions,
vwbSteps,
successRate: (successfulResolutions / totalTests) * 100,
};
}, [testResults]);
return (
<Box sx={{ p: 3, maxWidth: 1200, margin: '0 auto' }}>
<Typography variant="h4" gutterBottom sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<BugIcon color="primary" />
Test Debug - Propriétés d'Étapes
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
Ce composant teste la résolution des propriétés d'étapes pour diagnostiquer
pourquoi les paramètres apparaissent vides dans l'interface.
</Typography>
{/* Contrôles de test */}
<Card sx={{ mb: 3 }}>
<CardContent>
<Typography variant="h6" gutterBottom>
Contrôles de Test
</Typography>
<Box sx={{ display: 'flex', gap: 2, mb: 2 }}>
<Button
variant="contained"
onClick={testAllStepTypes}
startIcon={<BugIcon />}
>
Tester Tous les Types
</Button>
<Button
variant="outlined"
onClick={() => setTestResults([])}
>
Vider les Résultats
</Button>
</Box>
<Typography variant="body2" color="text.secondary">
Cliquez sur "Tester Tous les Types" pour exécuter les tests de résolution
des paramètres pour chaque type d'étape.
</Typography>
</CardContent>
</Card>
{/* Analyse des résultats */}
{analysisResults && (
<Card sx={{ mb: 3 }}>
<CardContent>
<Typography variant="h6" gutterBottom sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
{analysisResults.successRate === 100 ? (
<CheckIcon color="success" />
) : (
<ErrorIcon color="error" />
)}
Analyse des Résultats
</Typography>
<Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap', mb: 2 }}>
<Chip
label={`Total: ${analysisResults.totalTests}`}
color="primary"
/>
<Chip
label={`Succès: ${analysisResults.successfulResolutions}`}
color="success"
/>
<Chip
label={`Échecs: ${analysisResults.failedResolutions}`}
color="error"
/>
<Chip
label={`VWB: ${analysisResults.vwbSteps}`}
color="info"
/>
<Chip
label={`Taux: ${analysisResults.successRate.toFixed(1)}%`}
color={analysisResults.successRate === 100 ? 'success' : 'warning'}
/>
</Box>
{analysisResults.failedResolutions > 0 && (
<Alert severity="error" sx={{ mt: 2 }}>
<Typography variant="body2">
{analysisResults.failedResolutions} type(s) d'étapes ne résolvent pas leurs paramètres correctement.
Cela explique pourquoi les propriétés apparaissent vides dans l'interface.
</Typography>
</Alert>
)}
</CardContent>
</Card>
)}
{/* Configuration disponible */}
<Accordion sx={{ mb: 3 }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6">
Configuration stepParametersConfig Disponible
</Typography>
</AccordionSummary>
<AccordionDetails>
<TableContainer component={Paper}>
<Table size="small">
<TableHead>
<TableRow>
<TableCell>Type d'Étape</TableCell>
<TableCell>Nombre de Paramètres</TableCell>
<TableCell>Paramètres</TableCell>
</TableRow>
</TableHead>
<TableBody>
{Object.entries(stepParametersConfig).map(([stepType, config]) => (
<TableRow key={stepType}>
<TableCell>
<Chip label={stepType} size="small" />
</TableCell>
<TableCell>{config.length}</TableCell>
<TableCell>
{config.map(param => param.name).join(', ')}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</AccordionDetails>
</Accordion>
{/* Résultats des tests */}
{testResults.length > 0 && (
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6">
Résultats Détaillés des Tests ({testResults.length})
</Typography>
</AccordionSummary>
<AccordionDetails>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
{testResults.map((result, index) => (
<Card key={index} variant="outlined">
<CardContent>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
<Typography variant="h6">
Test: {result.stepType}
</Typography>
<Chip
label={result.resolvedConfigLength > 0 ? 'SUCCÈS' : 'ÉCHEC'}
color={result.resolvedConfigLength > 0 ? 'success' : 'error'}
/>
</Box>
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: 2 }}>
<Box>
<Typography variant="body2" color="text.secondary">
Configuration Directe
</Typography>
<Typography variant="body1">
{result.directConfigLength} paramètres
</Typography>
</Box>
<Box>
<Typography variant="body2" color="text.secondary">
Configuration Résolue
</Typography>
<Typography variant="body1">
{result.resolvedConfigLength} paramètres
</Typography>
</Box>
<Box>
<Typography variant="body2" color="text.secondary">
Est Action VWB
</Typography>
<Typography variant="body1">
{result.isVWBStep ? 'Oui' : 'Non'}
</Typography>
</Box>
<Box>
<Typography variant="body2" color="text.secondary">
Config Existe
</Typography>
<Typography variant="body1">
{result.configExists ? 'Oui' : 'Non'}
</Typography>
</Box>
</Box>
{result.resolvedConfigLength === 0 && result.configExists && (
<Alert severity="error" sx={{ mt: 2 }}>
<Typography variant="body2">
🚨 PROBLÈME IDENTIFIÉ: La configuration existe ({result.directConfigLength} paramètres)
mais la résolution retourne 0 paramètres. Cela indique un problème dans la logique
de résolution ou dans le mapping des types.
</Typography>
</Alert>
)}
<Accordion sx={{ mt: 2 }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="body2">
Détails Techniques
</Typography>
</AccordionSummary>
<AccordionDetails>
<Box component="pre" sx={{
fontSize: '0.75rem',
bgcolor: '#f5f5f5',
p: 1,
borderRadius: 1,
overflow: 'auto',
}}>
{JSON.stringify(result, null, 2)}
</Box>
</AccordionDetails>
</Accordion>
</CardContent>
</Card>
))}
</Box>
</AccordionDetails>
</Accordion>
)}
</Box>
);
};
export default PropertiesDebugTest;
'''
try:
# Créer le répertoire s'il n'existe pas
test_component_path.parent.mkdir(parents=True, exist_ok=True)
# Écrire le composant
with open(test_component_path, 'w', encoding='utf-8') as f:
f.write(test_component_content)
print(f"✅ Composant de test créé : {test_component_path}")
# Créer aussi un fichier de test simple
create_simple_test_script()
return True
except Exception as e:
print(f"❌ Erreur création composant de test : {e}")
return False
def create_simple_test_script():
"""Crée un script de test simple pour vérifier la logique."""
project_root = Path(__file__).parent.parent
test_script_path = project_root / "scripts" / "test_simple_proprietes_12jan2026.js"
test_script_content = '''/**
* Test Simple - Logique de Propriétés d'Étapes
* Auteur : Dom, Alice, Kiro - 12 janvier 2026
*
* Ce script teste la logique de base pour identifier le problème.
*/
// Configuration des paramètres (copie simplifiée)
const stepParametersConfig = {
click: [
{ name: 'target', label: 'Élément cible', type: 'visual', required: true },
{ name: 'clickType', label: 'Type de clic', type: 'select', defaultValue: 'left' },
],
type: [
{ name: 'target', label: 'Champ de saisie', type: 'visual', required: true },
{ name: 'text', label: 'Texte à saisir', type: 'text', required: true },
{ name: 'clearFirst', label: 'Vider le champ d\\'abord', type: 'boolean', defaultValue: true },
],
wait: [
{ name: 'duration', label: 'Durée (secondes)', type: 'number', required: true, defaultValue: 1 },
],
condition: [
{ name: 'condition', label: 'Condition', type: 'text', required: true },
],
extract: [
{ name: 'target', label: 'Élément source', type: 'visual', required: true },
{ name: 'attribute', label: 'Attribut à extraire', type: 'select', defaultValue: 'text' },
],
scroll: [
{ name: 'direction', label: 'Direction', type: 'select', defaultValue: 'down' },
{ name: 'amount', label: 'Quantité (pixels)', type: 'number', defaultValue: 300 },
],
navigate: [
{ name: 'url', label: 'URL de destination', type: 'text', required: true },
],
screenshot: [
{ name: 'filename', label: 'Nom du fichier', type: 'text' },
],
};
// Fonction de test (copie de PropertiesPanel)
function getParameterConfig(selectedStep) {
console.log('🔍 getParameterConfig appelée avec:', selectedStep);
if (!selectedStep) {
console.log('❌ selectedStep est null/undefined');
return [];
}
console.log('🔍 selectedStep.type:', selectedStep.type);
console.log('🔍 Type de selectedStep.type:', typeof selectedStep.type);
console.log('🔍 Clés disponibles dans stepParametersConfig:', Object.keys(stepParametersConfig));
const config = stepParametersConfig[selectedStep.type];
console.log('🔍 Configuration trouvée:', config);
console.log('🔍 Longueur de la configuration:', config ? config.length : 0);
const result = config || [];
console.log('✅ Résultat final:', result);
return result;
}
// Tests
console.log('🚀 Début des tests de logique de propriétés d\\'étapes');
console.log('=' .repeat(60));
const testSteps = [
{ id: 'test1', type: 'click', name: 'Test Click' },
{ id: 'test2', type: 'type', name: 'Test Type' },
{ id: 'test3', type: 'wait', name: 'Test Wait' },
{ id: 'test4', type: 'invalid', name: 'Test Invalid' },
{ id: 'test5', type: 'click_anchor', name: 'Test VWB Click' }, // Action VWB
];
testSteps.forEach((step, index) => {
console.log(`\\n🧪 Test ${index + 1}: ${step.name} (type: "${step.type}")`);
const config = getParameterConfig(step);
console.log(`📊 Résultat: ${config.length} paramètres trouvés`);
if (config.length > 0) {
console.log('✅ SUCCÈS - Paramètres disponibles:');
config.forEach(param => {
console.log(` - ${param.name}: ${param.label} (${param.type})`);
});
} else {
console.log('❌ ÉCHEC - Aucun paramètre trouvé');
// Diagnostic
if (stepParametersConfig[step.type]) {
console.log('🚨 PROBLÈME: Configuration existe mais non retournée!');
} else {
console.log(' INFO: Aucune configuration pour ce type (normal pour les actions VWB)');
}
}
});
console.log('\\n' + '=' .repeat(60));
console.log('📊 RÉSUMÉ DES TESTS');
console.log('=' .repeat(60));
// Résumé
const results = testSteps.map(step => ({
type: step.type,
configExists: !!stepParametersConfig[step.type],
paramCount: getParameterConfig(step).length,
}));
results.forEach(result => {
const status = result.paramCount > 0 ? '' : '';
console.log(`${status} ${result.type}: ${result.paramCount} paramètres (config existe: ${result.configExists})`);
});
const successCount = results.filter(r => r.paramCount > 0).length;
const totalCount = results.length;
console.log(`\\n📈 Taux de succès: ${successCount}/${totalCount} (${((successCount/totalCount)*100).toFixed(1)}%)`);
if (successCount < totalCount) {
console.log('\\n🔧 RECOMMANDATIONS:');
console.log('1. Vérifier que tous les types d\\'étapes ont une configuration');
console.log('2. Vérifier la logique de détection des actions VWB');
console.log('3. Ajouter des logs dans le composant React pour déboguer en temps réel');
}
console.log('\\n✅ Tests terminés');
'''
try:
with open(test_script_path, 'w', encoding='utf-8') as f:
f.write(test_script_content)
print(f"✅ Script de test simple créé : {test_script_path}")
return True
except Exception as e:
print(f"❌ Erreur création script de test : {e}")
return False
def main():
"""Fonction principale."""
print("🧪 Création des outils de test pour déboguer les propriétés d'étapes")
success = create_debug_component()
if success:
print("\n✅ Outils de test créés avec succès!")
print("\n📋 PROCHAINES ÉTAPES:")
print("1. Intégrer le composant PropertiesDebugTest dans l'application")
print("2. Exécuter le script de test simple avec Node.js")
print("3. Analyser les résultats pour identifier le problème exact")
print("4. Implémenter la correction basée sur les résultats")
print("\n🔧 COMMANDES À EXÉCUTER:")
print("# Test simple JavaScript:")
print("node scripts/test_simple_proprietes_12jan2026.js")
print("\n# Intégrer le composant de test dans App.tsx (temporairement)")
print("# Puis tester dans le navigateur")
return 0
else:
print("\n❌ Échec de la création des outils de test")
return 1
if __name__ == "__main__":
sys.exit(main())