clean: remove tests

This commit is contained in:
2025-08-05 21:23:49 +02:00
parent 91eb04ca01
commit 8708606d4f
14 changed files with 0 additions and 1142 deletions

View File

@@ -1,94 +0,0 @@
#!/usr/bin/env python3
"""
Test manuel pour vérifier le bon fonctionnement du système de configuration.
"""
from app import create_app
from app_config import config_manager
from models import CompetenceScaleValue
def test_config_system():
"""Test manuel du système de configuration."""
app = create_app('development')
with app.app_context():
print("=== Test du Système de Configuration ===\n")
# 1. Test récupération des valeurs d'échelle
print("1. Récupération des valeurs d'échelle:")
scale_values = config_manager.get_competence_scale_values()
for value, config in scale_values.items():
print(f" {value}: {config['label']} (couleur: {config['color']}, inclus: {config['included_in_total']})")
print()
# 2. Test modification d'une valeur
print("2. Test modification de la valeur '2':")
print(f" Avant: {scale_values['2']['label']}")
success = config_manager.update_scale_value('2', 'Acquis (modifié)', '#00ff00', True)
print(f" Modification réussie: {success}")
updated_values = config_manager.get_competence_scale_values()
print(f" Après: {updated_values['2']['label']}")
print()
# 3. Test ajout d'une nouvelle valeur
print("3. Test ajout d'une nouvelle valeur 'X':")
success = config_manager.add_scale_value('X', 'Test Value', '#purple', False)
print(f" Ajout réussi: {success}")
updated_values = config_manager.get_competence_scale_values()
if 'X' in updated_values:
print(f" Nouvelle valeur: X = {updated_values['X']['label']}")
print()
# 4. Test validation
print("4. Test validation des valeurs:")
test_values = [
('0', 'score'),
('3', 'score'),
('4', 'score'), # Invalid
('15.5', 'notes'),
('.', 'notes'),
('X', 'score'), # Notre nouvelle valeur
]
for value, grading_type in test_values:
valid = config_manager.validate_grade_value(value, grading_type)
print(f" {value} ({grading_type}): {'✓ Valide' if valid else '✗ Invalide'}")
print()
# 5. Test informations d'affichage
print("5. Test informations d'affichage:")
display_tests = [
('2', 'score'),
('.', 'notes'),
('15.5', 'notes'),
('X', 'score'),
]
for value, grading_type in display_tests:
info = config_manager.get_display_info(value, grading_type)
print(f" {value}: {info['label']} (couleur: {info['color']})")
print()
# 6. Test suppression
print("6. Test suppression de la valeur 'X':")
success = config_manager.delete_scale_value('X')
print(f" Suppression réussie: {success}")
final_values = config_manager.get_competence_scale_values()
print(f" 'X' encore présente: {'X' in final_values}")
print()
# 7. Vérification cohérence avec la base de données
print("7. Vérification cohérence base de données:")
db_values = CompetenceScaleValue.query.all()
print(f" Nombre de valeurs en base: {len(db_values)}")
print(f" Nombre de valeurs via config_manager: {len(final_values)}")
print()
print("=== Test terminé avec succès ===")
if __name__ == '__main__':
test_config_system()

View File

@@ -1,190 +0,0 @@
#!/usr/bin/env python3
"""
Test final complet pour valider que tout le système de valeurs spéciales
fonctionne correctement et est entièrement flexible.
"""
from app import create_app
from app_config import config_manager
from models import db, Grade
import re
def test_final_complete():
"""Test final complet du système flexible."""
app = create_app('development')
with app.app_context():
print("=== TEST FINAL COMPLET : Système flexible des valeurs spéciales ===\n")
# 1. Configuration de base
print("1. État de la configuration:")
scale_values = config_manager.get_competence_scale_values()
special_values = [v for v in scale_values.keys() if v not in ['0', '1', '2', '3']]
print(f" Valeurs spéciales configurées: {special_values}")
for value in special_values:
config = scale_values[value]
print(f" '{value}': {config['label']} (couleur: {config['color']})")
print()
# 2. Test de flexibilité - ajouter une nouvelle valeur spéciale
print("2. Test de flexibilité - Ajout d'une nouvelle valeur 'x':")
success = config_manager.add_scale_value('x', 'Excusé', '#9ca3af', False)
print(f" Ajout de 'x' (Excusé): {success}")
if success:
# Vérifier que la nouvelle valeur est prise en compte
updated_values = config_manager.get_competence_scale_values()
if 'x' in updated_values:
print(f" ✅ Nouvelle valeur 'x': {updated_values['x']['label']}")
else:
print(" ❌ Nouvelle valeur 'x' non trouvée")
print()
# 3. Test de l'interface avec la nouvelle valeur
print("3. Test de l'interface avec la nouvelle valeur:")
with app.test_client() as client:
response = client.get('/assessments/1/grading')
content = response.get_data(as_text=True)
# Vérifier les champs INPUT
if 'type="text"' in content:
print(" ✅ Champs INPUT de type 'text' (permettent valeurs spéciales)")
else:
print(" ❌ Champs INPUT toujours de type 'number'")
# Vérifier le placeholder
placeholder_match = re.search(r'placeholder="([^"]*)"', content)
if placeholder_match:
placeholder = placeholder_match.group(1)
if 'x' in placeholder:
print(f" ✅ Placeholder inclut nouvelle valeur 'x': '{placeholder}'")
else:
print(f" 📋 Placeholder: '{placeholder}' (peut ne pas encore inclure 'x')")
# Vérifier la config JavaScript
js_start = content.find('special_values: {')
if js_start != -1:
js_end = js_start + 500
js_config = content[js_start:js_end]
if "'x'" in js_config:
print(" ✅ Nouvelle valeur 'x' présente dans la config JavaScript")
else:
print(" 📋 Nouvelle valeur 'x' peut ne pas être encore dans le JS (cache possible)")
# Vérifier les options SELECT
if 'value="x"' in content:
print(" ✅ Nouvelle valeur 'x' présente dans les options SELECT")
else:
print(" 📋 Nouvelle valeur 'x' peut ne pas être encore dans les SELECT")
print()
# 4. Test de saisie avec toutes les valeurs
print("4. Test de saisie avec toutes les valeurs:")
# Nettoyer les données existantes
Grade.query.filter_by(student_id=1).delete()
db.session.commit()
# Test avec toutes les valeurs spéciales existantes + nouvelles
all_special_values = [v for v in config_manager.get_competence_scale_values().keys()
if v not in ['0', '1', '2', '3']]
with app.test_client() as client:
test_data = {}
for i, value in enumerate(all_special_values[:3], 1): # Tester les 3 premières
test_data[f'grade_1_{i}'] = value
print(f" Données de test: {test_data}")
response = client.post('/assessments/1/grading/save',
data=test_data,
follow_redirects=False)
print(f" Soumission: statut {response.status_code}")
if response.status_code == 302:
print(" ✅ Toutes les valeurs spéciales acceptées par le serveur")
# Vérifier les valeurs sauvées
grades = Grade.query.filter_by(student_id=1).all()
for grade in grades:
display_info = config_manager.get_display_info(grade.value, 'score')
print(f" Sauvé: '{grade.value}'{display_info['label']}")
else:
print(" ❌ Erreur lors de la soumission")
print()
# 5. Test des raccourcis clavier dynamiques
print("5. Test des raccourcis clavier dynamiques:")
with app.test_client() as client:
response = client.get('/assessments/1/grading')
content = response.get_data(as_text=True)
# Vérifier que le JavaScript utilise la liste dynamique
if 'SPECIAL_VALUES_KEYS.includes(e.key)' in content:
print(" ✅ JavaScript utilise la liste dynamique SPECIAL_VALUES_KEYS")
else:
print(" ❌ JavaScript utilise encore une liste hard-codée")
# Vérifier la définition de SPECIAL_VALUES_KEYS
if 'const SPECIAL_VALUES_KEYS = Object.keys(GRADING_CONFIG.special_values);' in content:
print(" ✅ SPECIAL_VALUES_KEYS défini dynamiquement")
else:
print(" ❌ SPECIAL_VALUES_KEYS non trouvé")
print()
# 6. Test de validation
print("6. Test de validation:")
test_cases = [
('.', 'notes', True, 'Valeur spéciale existante'),
('d', 'notes', True, 'Valeur spéciale existante'),
('x', 'notes', True, 'Nouvelle valeur spéciale'),
('15.5', 'notes', True, 'Valeur numérique valide'),
('abc', 'notes', False, 'Valeur invalide'),
('-5', 'notes', False, 'Valeur négative'),
]
for value, grade_type, expected, description in test_cases:
is_valid = config_manager.validate_grade_value(value, grade_type)
status = "" if is_valid == expected else ""
print(f" {status} {description}: '{value}'{is_valid} (attendu: {expected})")
print()
# 7. Nettoyage - Supprimer la valeur de test
print("7. Nettoyage:")
if 'x' in config_manager.get_competence_scale_values():
success = config_manager.delete_scale_value('x')
print(f" Suppression de la valeur de test 'x': {success}")
print()
# 8. Résumé final
print("8. RÉSUMÉ FINAL - SYSTÈME FLEXIBLE :")
features = [
"✅ Champs INPUT de type 'text' permettent la saisie libre",
"✅ JavaScript entièrement dynamique (plus de hard-coding)",
"✅ Placeholder généré automatiquement selon la configuration",
"✅ Validation côté client et serveur",
"✅ Configuration centralisée et flexible",
"✅ Interface de configuration web fonctionnelle",
"✅ Ajout/suppression de valeurs spéciales en temps réel",
"✅ Raccourcis clavier s'adaptent automatiquement",
]
for feature in features:
print(f" {feature}")
print("\n 🎉 SUCCÈS COMPLET : Le système est maintenant entièrement flexible !")
print(" 📋 Fonctionnalités validées:")
print(" - Saisie libre des valeurs spéciales dans tous les champs")
print(" - Configuration dynamique sans redémarrage")
print(" - Interface utilisateur qui s'adapte automatiquement")
print(" - Validation robuste côté client et serveur")
print(" - Aucune valeur hard-codée dans le code")
print("\n=== Fin du test complet ===")
if __name__ == '__main__':
test_final_complete()

View File

@@ -1,151 +0,0 @@
#!/usr/bin/env python3
"""
Test pour vérifier que les champs INPUT notes permettent maintenant
la saisie des valeurs spéciales et que le JavaScript est dynamique.
"""
from app import create_app
from app_config import config_manager
import re
def test_input_notes_fixed():
"""Test des corrections pour les champs INPUT notes."""
app = create_app('development')
with app.app_context():
print("=== TEST : Corrections champs INPUT notes ===\n")
# 1. Vérifier que les champs sont maintenant de type 'text'
print("1. Vérification du type des champs INPUT:")
with app.test_client() as client:
response = client.get('/assessments/1/grading')
content = response.get_data(as_text=True)
# Chercher les champs input de type notes
input_pattern = r'<input[^>]*data-type="notes"[^>]*>'
inputs = re.findall(input_pattern, content)
print(f" Champs INPUT notes trouvés: {len(inputs)}")
for i, input_html in enumerate(inputs[:2], 1): # Examiner les 2 premiers
if 'type="text"' in input_html:
print(f" ✅ Champ {i}: type='text' (permet valeurs spéciales)")
elif 'type="number"' in input_html:
print(f" ❌ Champ {i}: type='number' (bloque valeurs spéciales)")
else:
print(f" ⚠️ Champ {i}: type non spécifié")
# Vérifier le placeholder
placeholder_match = re.search(r'placeholder="([^"]*)"', input_html)
if placeholder_match:
placeholder = placeholder_match.group(1)
print(f" Placeholder: '{placeholder}'")
print()
# 2. Vérifier la configuration JavaScript dynamique
print("2. Vérification du JavaScript dynamique:")
with app.test_client() as client:
response = client.get('/assessments/1/grading')
content = response.get_data(as_text=True)
# Vérifier la présence de SPECIAL_VALUES_KEYS
if 'const SPECIAL_VALUES_KEYS = Object.keys(GRADING_CONFIG.special_values);' in content:
print(" ✅ Variable SPECIAL_VALUES_KEYS définie dynamiquement")
else:
print(" ❌ Variable SPECIAL_VALUES_KEYS manquante")
# Vérifier l'utilisation de SPECIAL_VALUES_KEYS
if 'SPECIAL_VALUES_KEYS.includes(e.key)' in content:
print(" ✅ Utilisation dynamique de SPECIAL_VALUES_KEYS dans handleGradeKeydown")
else:
print(" ❌ Code utilise encore la liste hard-codée")
# Vérifier la fonction de validation
if 'function validateGradeValue(' in content:
print(" ✅ Fonction de validation validateGradeValue présente")
else:
print(" ❌ Fonction de validation manquante")
print()
# 3. Vérifier les valeurs spéciales configurées
print("3. Valeurs spéciales actuellement configurées:")
scale_values = config_manager.get_competence_scale_values()
special_values = [v for v in scale_values.keys() if v in ['.', 'd', 'a']]
print(f" Valeurs spéciales configurées: {special_values}")
for value in special_values:
config = scale_values[value]
print(f" '{value}': {config['label']} (couleur: {config['color']})")
print()
# 4. Test de la configuration JavaScript générée
print("4. Configuration JavaScript des valeurs spéciales:")
with app.test_client() as client:
response = client.get('/assessments/1/grading')
content = response.get_data(as_text=True)
# Extraire la section special_values
start = content.find('special_values: {')
if start != -1:
end = content.find('}', start) + 1
js_config = content[start:end]
print(f" {js_config}")
# Vérifier que toutes les valeurs configurées sont présentes
all_present = True
for value in special_values:
if f"'{value}'" in js_config:
print(f"'{value}' présent dans la config JS")
else:
print(f"'{value}' absent de la config JS")
all_present = False
if all_present:
print(" ✅ Toutes les valeurs spéciales sont dans la config JS")
else:
print(" ❌ Configuration JavaScript non trouvée")
print()
# 5. Test de saisie simulée
print("5. Test de saisie avec valeurs spéciales:")
# Test de validation côté serveur
test_cases = [
('.', 'notes', 'Valeur spéciale point'),
('d', 'notes', 'Valeur spéciale dispensé'),
('15.5', 'notes', 'Valeur numérique valide'),
('abc', 'notes', 'Valeur invalide'),
]
for value, grade_type, description in test_cases:
is_valid = config_manager.validate_grade_value(value, grade_type)
status = "" if is_valid else ""
print(f" {status} {description}: '{value}'{is_valid}")
print()
# 6. Résumé des améliorations
print("6. RÉSUMÉ DES AMÉLIORATIONS:")
improvements = [
"Champs INPUT changés de type='number' à type='text'",
"Placeholder dynamique basé sur les valeurs configurées",
"JavaScript utilise maintenant SPECIAL_VALUES_KEYS dynamique",
"Plus de valeurs hard-codées ['.', 'd', 'a']",
"Fonction de validation validateGradeValue ajoutée",
"Validation immédiate avec feedback visuel",
]
for improvement in improvements:
print(f"{improvement}")
print("\n 🎉 SUCCÈS : Les champs INPUT notes sont maintenant flexibles !")
print(" 📋 L'utilisateur peut maintenant:")
print(" - Taper directement les valeurs spéciales dans les champs notes")
print(" - Bénéficier d'une validation immédiate avec feedback visuel")
print(" - Utiliser les raccourcis clavier pour toutes les valeurs configurées")
print(" - Le système s'adapte automatiquement aux nouvelles valeurs ajoutées")
print("\n=== Fin du test ===")
if __name__ == '__main__':
test_input_notes_fixed()

View File

@@ -1,91 +0,0 @@
#!/usr/bin/env python3
"""
Test pour vérifier que les modifications de configuration sont bien
prises en compte dans l'interface de notation.
"""
from app import create_app
from app_config import config_manager
from models import db, Assessment, Student, GradingElement
def test_interface_sync():
"""Test que l'interface de notation utilise les bonnes valeurs."""
app = create_app('development')
with app.app_context():
print("=== TEST : Synchronisation interface de notation ===\n")
# 1. Modifier une valeur d'échelle
print("1. Modification d'un label dans la configuration:")
success = config_manager.update_scale_value('2', 'SUPER ACQUIS', '#00ff00', True)
print(f" Modification du label '2''SUPER ACQUIS': {success}")
# 2. Vérifier que get_display_info retourne la bonne valeur
display_info = config_manager.get_display_info('2', 'score')
print(f" get_display_info('2', 'score'): {display_info}")
# 3. Simuler l'appel à la route de notation
assessment = Assessment.query.first()
if assessment:
print(f"\n2. Test avec une évaluation réelle: {assessment.title}")
students = Student.query.filter_by(class_group_id=assessment.class_group_id).all()
grading_elements = []
for exercise in assessment.exercises:
for element in exercise.grading_elements:
grading_elements.append(element)
# Simuler ce que fait la route
scale_values = config_manager.get_competence_scale_values()
print(f" Nombre d'étudiants: {len(students)}")
print(f" Nombre d'éléments de notation: {len(grading_elements)}")
print(f" scale_values['2']['label']: '{scale_values['2']['label']}'")
# 4. Vérifier les éléments de type 'score'
score_elements = [e for e in grading_elements if e.grading_type == 'score']
print(f" Éléments de type 'score': {len(score_elements)}")
for element in score_elements[:2]: # Tester les 2 premiers
print(f" - {element.label} (type: {element.grading_type})")
# Simuler l'affichage des options
for value in ['0', '1', '2', '3']:
display_info = config_manager.get_display_info(value, 'score')
print(f" Option {value}: '{display_info['label']}' (couleur: {display_info['color']})")
# 5. Test des valeurs spéciales
print("\n3. Test des valeurs spéciales:")
special_values = ['.', 'd', 'a']
for value in special_values:
if value in scale_values:
display_info = config_manager.get_display_info(value, 'score')
print(f" Valeur '{value}': '{display_info['label']}' (couleur: {display_info['color']})")
# 6. Test avec une requête HTTP simulée
print("\n4. Test d'accès à la route de notation:")
with app.test_client() as client:
if assessment:
response = client.get(f'/assessments/{assessment.id}/grading')
print(f" Statut de la réponse: {response.status_code}")
if response.status_code == 200:
content = response.get_data(as_text=True)
# Vérifier que le label modifié apparaît dans le HTML
if 'SUPER ACQUIS' in content:
print(" ✅ Label modifié 'SUPER ACQUIS' trouvé dans le HTML")
else:
print(" ❌ Label modifié 'SUPER ACQUIS' NOT FOUND dans le HTML")
# Chercher ce qui apparaît à la place
import re
matches = re.findall(r'value="2"[^>]*>2 \(([^)]+)\)', content)
if matches:
print(f" 📋 Label actuel pour '2': '{matches[0]}'")
else:
print(f" ❌ Erreur d'accès à la route: {response.status_code}")
print("\n=== Fin du test ===")
if __name__ == '__main__':
test_interface_sync()

View File

@@ -1,18 +0,0 @@
#!/usr/bin/env python3
from app import create_app
app = create_app('development')
with app.test_client() as client:
response = client.get('/assessments/1/grading')
content = response.get_data(as_text=True)
# Chercher la section special_values
start = content.find('special_values: {')
if start != -1:
end = content.find('}', start) + 1
config_section = content[start:end]
print('Configuration JavaScript:')
print(config_section)
else:
print('Section special_values non trouvée')

View File

@@ -1,146 +0,0 @@
#!/usr/bin/env python3
"""
Test diagnostic pour identifier pourquoi les modifications des labels
ne sont pas prises en compte dans l'application.
"""
from app import create_app
from app_config import config_manager
from models import db, CompetenceScaleValue, GradingElement, Grade
import json
def diagnostic_label_sync():
"""Test diagnostic pour les problèmes de synchronisation des labels."""
app = create_app('development')
with app.app_context():
print("=== DIAGNOSTIC : Problème de synchronisation des labels ===\n")
# 1. État initial des valeurs d'échelle
print("1. État initial des valeurs d'échelle:")
initial_values = config_manager.get_competence_scale_values()
for value, config in initial_values.items():
print(f" {value}: '{config['label']}' (couleur: {config['color']})")
print()
# 2. Tester une modification d'un label via config_manager
print("2. Test modification du label '2' via config_manager:")
old_label = initial_values['2']['label']
print(f" Ancien label pour '2': '{old_label}'")
success = config_manager.update_scale_value('2', 'ACQUIS MODIFIÉ', '#ff0000', True)
print(f" Modification réussie: {success}")
# Vérifier que la modification a été prise en compte
updated_values = config_manager.get_competence_scale_values()
new_label = updated_values['2']['label']
print(f" Nouveau label pour '2': '{new_label}'")
print()
# 3. Tester get_display_info après modification
print("3. Test get_display_info après modification:")
display_info = config_manager.get_display_info('2', 'score')
print(f" get_display_info('2', 'score'): {display_info}")
print()
# 4. Vérifier directement dans la base de données
print("4. Vérification directe dans la base de données:")
db_value = CompetenceScaleValue.query.get('2')
if db_value:
print(f" Base de données - label pour '2': '{db_value.label}'")
print(f" Base de données - couleur pour '2': '{db_value.color}'")
else:
print(" ERREUR: Valeur '2' non trouvée en base de données")
print()
# 5. Tester les valeurs utilisées dans des templates simulés
print("5. Test des sources de données pour templates:")
# get_competence_scale_values (utilisé dans templates)
template_values = config_manager.get_competence_scale_values()
print(f" Template source (get_competence_scale_values): '{template_values['2']['label']}'")
# get_score_meanings (configuration statique)
score_meanings = config_manager.get_score_meanings()
print(f" Score meanings statique: '{score_meanings[2]['label']}'")
print()
# 6. Test avec un élément de notation réel
print("6. Test avec éléments de notation existants:")
grading_elements = GradingElement.query.filter_by(grading_type='score').limit(3).all()
for element in grading_elements:
print(f" Élément: {element.label} (type: {element.grading_type})")
# Chercher des grades pour cet élément
grades = Grade.query.filter_by(grading_element_id=element.id).limit(3).all()
for grade in grades:
if grade.value in ['0', '1', '2', '3']:
display_info = config_manager.get_display_info(grade.value, element.grading_type)
print(f" Grade {grade.value} → Display: '{display_info['label']}' (couleur: {display_info['color']})")
print()
# 7. Test des différentes méthodes d'affichage
print("7. Comparaison des différentes sources de labels:")
test_value = '2'
# Source 1: get_competence_scale_values (DB)
scale_values = config_manager.get_competence_scale_values()
source1 = scale_values[test_value]['label'] if test_value in scale_values else "NOT FOUND"
# Source 2: get_display_info (DB via get_competence_scale_values)
display_info = config_manager.get_display_info(test_value, 'score')
source2 = display_info['label']
# Source 3: get_score_meanings (statique)
score_meanings = config_manager.get_score_meanings()
source3 = score_meanings[int(test_value)]['label'] if int(test_value) in score_meanings else "NOT FOUND"
print(f" get_competence_scale_values: '{source1}'")
print(f" get_display_info: '{source2}'")
print(f" get_score_meanings: '{source3}'")
print()
# 8. Diagnostic de cohérence
print("8. Diagnostic de cohérence:")
inconsistencies = []
for i in range(4): # Tester 0, 1, 2, 3
value_str = str(i)
if value_str in scale_values and i in score_meanings:
db_label = scale_values[value_str]['label']
static_label = score_meanings[i]['label']
if db_label != static_label:
inconsistencies.append({
'value': value_str,
'db_label': db_label,
'static_label': static_label
})
if inconsistencies:
print(" 🚨 INCOHÉRENCES DÉTECTÉES:")
for inc in inconsistencies:
print(f" Valeur {inc['value']}: DB='{inc['db_label']}' vs Static='{inc['static_label']}'")
else:
print(" ✅ Aucune incohérence détectée")
print()
# 9. Recommandations
print("9. Recommandations pour corriger le problème:")
if inconsistencies:
print(" 📋 Actions recommandées:")
print(" - Les templates utilisent probablement get_score_meanings au lieu de get_competence_scale_values")
print(" - Vérifier tous les templates qui affichent des labels de scores")
print(" - S'assurer que get_display_info utilise bien la base de données")
print(" - Mettre à jour get_score_meanings pour utiliser les valeurs DB ou supprimer cette méthode")
else:
print(" ✅ Configuration cohérente")
print(" - Vérifier si le cache du navigateur pose problème")
print(" - Tester la page de notation en direct")
print("\n=== Fin du diagnostic ===")
if __name__ == '__main__':
diagnostic_label_sync()

View File

@@ -1,202 +0,0 @@
#!/usr/bin/env python3
"""
Test approfondi pour comprendre pourquoi les valeurs spéciales
ne fonctionnent pas dans l'interface utilisateur.
"""
from app import create_app
from app_config import config_manager
from models import db, Assessment, Student, GradingElement, Grade
import re
def test_special_values_ui():
"""Test approfondi de l'interface utilisateur pour les valeurs spéciales."""
app = create_app('development')
with app.app_context():
print("=== DIAGNOSTIC APPROFONDI : Valeurs spéciales UI ===\n")
# 1. Vérifier les valeurs spéciales dans scale_values
print("1. Configuration des valeurs spéciales:")
scale_values = config_manager.get_competence_scale_values()
for key, config in scale_values.items():
if key in ['.', 'd']:
print(f" '{key}': {config}")
print()
# 2. Examiner le HTML généré pour les selects
print("2. Analyse du HTML généré pour les champs select:")
with app.test_client() as client:
response = client.get('/assessments/1/grading')
if response.status_code == 200:
content = response.get_data(as_text=True)
# Extraire toutes les options des selects
option_pattern = r'<option value="([^"]*)"[^>]*>([^<]*)</option>'
options = re.findall(option_pattern, content)
print(" Options trouvées dans les selects:")
special_found = False
for value, text in options[:20]: # Afficher les 20 premières
if value in ['.', 'd']:
print(f" ✅ value=\"{value}\"{text}")
special_found = True
elif value in ['0', '1', '2', '3']:
print(f" 📋 value=\"{value}\"{text}")
if not special_found:
print(" ❌ Aucune valeur spéciale trouvée dans les options")
print()
# 3. Tester l'interface avec des éléments de type 'notes' vs 'score'
print("3. Test par type d'élément de notation:")
assessment = Assessment.query.first()
if assessment:
grading_elements = []
for exercise in assessment.exercises:
for element in exercise.grading_elements:
grading_elements.append(element)
score_elements = [e for e in grading_elements if e.grading_type == 'score']
notes_elements = [e for e in grading_elements if e.grading_type == 'notes']
print(f" Éléments 'score': {len(score_elements)}")
print(f" Éléments 'notes': {len(notes_elements)}")
for element in score_elements[:2]:
print(f" Score: {element.label} (type: {element.grading_type})")
for element in notes_elements[:2]:
print(f" Notes: {element.label} (type: {element.grading_type})")
print()
# 4. Vérifier le JavaScript - chercher les configurations
print("4. Analyse du JavaScript dans le template:")
with app.test_client() as client:
response = client.get('/assessments/1/grading')
if response.status_code == 200:
content = response.get_data(as_text=True)
# Chercher la configuration JavaScript
js_config_pattern = r'special_values:\s*\{([^}]+)\}'
js_match = re.search(js_config_pattern, content, re.DOTALL)
if js_match:
js_config = js_match.group(1)
print(" Configuration JavaScript des valeurs spéciales:")
print(f" {js_config.strip()}")
# Vérifier si . et d sont dans la config JS
if "'.':" in js_config:
print(" ✅ Valeur '.' trouvée dans la config JS")
else:
print(" ❌ Valeur '.' NON trouvée dans la config JS")
if "'d':" in js_config:
print(" ✅ Valeur 'd' trouvée dans la config JS")
else:
print(" ❌ Valeur 'd' NON trouvée dans la config JS")
else:
print(" ❌ Configuration JavaScript des valeurs spéciales NON trouvée")
print()
# 5. Tester la navigation clavier JavaScript
print("5. Test de la logique JavaScript pour valeurs spéciales:")
with app.test_client() as client:
response = client.get('/assessments/1/grading')
if response.status_code == 200:
content = response.get_data(as_text=True)
# Chercher la fonction handleGradeKeydown
keydown_pattern = r'function handleGradeKeydown.*?\{(.*?)\n\}'
keydown_match = re.search(keydown_pattern, content, re.DOTALL)
if keydown_match:
keydown_function = keydown_match.group(1)
print(" Fonction handleGradeKeydown trouvée")
# Vérifier si les valeurs spéciales sont gérées
if '[\'.\', \'d\', \'a\']' in keydown_function:
print(" ✅ Gestion des valeurs spéciales dans handleGradeKeydown")
else:
print(" ❌ Pas de gestion des valeurs spéciales dans handleGradeKeydown")
# Extraire la partie relevant des valeurs spéciales
special_handling = re.search(r'if \(\[.*?\]\.includes\(e\.key\)\).*?\}', keydown_function, re.DOTALL)
if special_handling:
print(f" Gestion des valeurs spéciales:")
print(f" {special_handling.group(0)[:200]}...")
else:
print(" ❌ Fonction handleGradeKeydown NON trouvée")
print()
# 6. Test de saisie manuelle simulée
print("6. Test de saisie manuelle:")
# Simuler ce qui se passe quand on tape '.' ou 'd'
test_cases = [
('1', '1', '.'), # student_id, element_id, value
('1', '2', 'd'),
('1', '3', '2'), # valeur normale pour comparaison
]
with app.test_client() as client:
for student_id, element_id, value in test_cases:
form_data = {f'grade_{student_id}_{element_id}': value}
response = client.post('/assessments/1/grading/save',
data=form_data,
follow_redirects=False)
print(f" Saisie '{value}': statut {response.status_code}")
# Vérifier si la valeur a été sauvée
grade = Grade.query.filter_by(
student_id=student_id,
grading_element_id=element_id
).first()
if grade:
print(f" → Valeur en base: '{grade.value}'")
else:
print(" → Aucune valeur en base")
print()
# 7. Diagnostic des problèmes potentiels
print("7. DIAGNOSTIC FINAL:")
problems = []
# Vérifier si les valeurs spéciales ont bien les options dans les selects
with app.test_client() as client:
response = client.get('/assessments/1/grading')
content = response.get_data(as_text=True)
if 'value="."' not in content:
problems.append("Options select pour '.' manquantes")
if 'value="d"' not in content:
problems.append("Options select pour 'd' manquantes")
# Vérifier les champs input (type notes)
if 'placeholder="0 ou . d a"' in content:
print(" ✅ Placeholder indique que les valeurs spéciales sont supportées pour 'notes'")
else:
problems.append("Placeholder ne mentionne pas les valeurs spéciales")
if problems:
print(" 🚨 PROBLÈMES IDENTIFIÉS:")
for problem in problems:
print(f" - {problem}")
else:
print(" ✅ Configuration semble correcte")
print(" 📋 Le problème pourrait être dans l'interaction utilisateur")
print("\n=== Fin du diagnostic ===")
if __name__ == '__main__':
test_special_values_ui()

View File

@@ -1,155 +0,0 @@
#!/usr/bin/env python3
"""
Test pour comprendre exactement comment l'utilisateur essaie
de saisir les valeurs spéciales et pourquoi ça ne marche pas.
"""
from app import create_app
from app_config import config_manager
import re
def test_ui_interaction():
"""Test des interactions utilisateur pour valeurs spéciales."""
app = create_app('development')
with app.app_context():
print("=== DIAGNOSTIC : Interaction utilisateur valeurs spéciales ===\n")
# 1. Vérifier exactement ce que voit l'utilisateur
print("1. HTML exact généré pour un champ de type 'score':")
with app.test_client() as client:
response = client.get('/assessments/1/grading')
content = response.get_data(as_text=True)
# Extraire un exemple de select complet
select_pattern = r'(<select[^>]*name="grade_\d+_\d+"[^>]*>.*?</select>)'
select_match = re.search(select_pattern, content, re.DOTALL)
if select_match:
select_html = select_match.group(1)
print(" SELECT complet:")
# Nettoyer l'affichage
lines = select_html.split('\n')
for line in lines[:15]: # Afficher les 15 premières lignes
print(f" {line.strip()}")
print(" ...")
else:
print(" ❌ Aucun select trouvé")
print()
# 2. Vérifier exactement ce que voit l'utilisateur pour les champs 'notes'
print("2. HTML exact généré pour un champ de type 'notes':")
with app.test_client() as client:
response = client.get('/assessments/1/grading')
content = response.get_data(as_text=True)
# Extraire un exemple d'input de type notes
input_pattern = r'(<input[^>]*data-type="notes"[^>]*>)'
input_match = re.search(input_pattern, content)
if input_match:
input_html = input_match.group(1)
print(" INPUT notes:")
print(f" {input_html}")
else:
print(" ❌ Aucun input notes trouvé")
print()
# 3. Analyser les comportements possibles
print("3. Analyse des comportements possibles:")
print(" Pour les champs SELECT (type 'score'):")
print(" - L'utilisateur doit SÉLECTIONNER l'option dans la liste déroulante")
print(" - Taper '.' ou 'd' au clavier PEUT fonctionner avec le JavaScript")
print(" - Mais il faut que l'option existe dans le select")
print(" Pour les champs INPUT (type 'notes'):")
print(" - L'utilisateur peut TAPER directement '.' ou 'd'")
print(" - Le placeholder indique que c'est supporté")
print(" - Le JavaScript gère les touches spéciales")
print()
# 4. Test spécifique de l'interaction clavier
print("4. Test du JavaScript de gestion clavier:")
with app.test_client() as client:
response = client.get('/assessments/1/grading')
content = response.get_data(as_text=True)
# Chercher la fonction handleGradeKeydown complète
keydown_start = content.find('function handleGradeKeydown')
if keydown_start != -1:
# Trouver la fin de la fonction
brace_count = 0
func_start = content.find('{', keydown_start)
i = func_start + 1
while i < len(content) and not (brace_count == 0 and content[i] == '}'):
if content[i] == '{':
brace_count += 1
elif content[i] == '}':
brace_count -= 1
i += 1
if i < len(content):
keydown_function = content[keydown_start:i+1]
# Extraire la partie des valeurs spéciales
special_part = re.search(r'if \(\[.*?\]\.includes\(e\.key\)\).*?return;', keydown_function, re.DOTALL)
if special_part:
print(" Gestion JavaScript des valeurs spéciales:")
special_code = special_part.group(0)
lines = special_code.split('\n')
for line in lines:
print(f" {line.strip()}")
else:
print(" ❌ Pas de gestion des valeurs spéciales trouvée")
else:
print(" ❌ Fonction handleGradeKeydown non trouvée")
print()
# 5. Identifier les problèmes potentiels
print("5. PROBLÈMES POTENTIELS IDENTIFIÉS:")
problems = []
solutions = []
# Vérifier si la configuration JavaScript est correcte
with app.test_client() as client:
response = client.get('/assessments/1/grading')
content = response.get_data(as_text=True)
# Configuration JavaScript
if "special_values: {" in content:
js_config_start = content.find("special_values: {")
js_config_end = content.find("}", js_config_start) + 1
js_config = content[js_config_start:js_config_end]
if "'.':" not in js_config:
problems.append("Valeur '.' manquante dans la config JavaScript")
solutions.append("Corriger la génération du JavaScript pour inclure '.'")
if "'d':" not in js_config:
problems.append("Valeur 'd' manquante dans la config JavaScript")
solutions.append("Corriger la génération du JavaScript pour inclure 'd'")
print(f" Configuration JavaScript actuelle:")
print(f" {js_config}")
else:
problems.append("Configuration JavaScript des valeurs spéciales manquante")
if problems:
print("\n 🚨 PROBLÈMES:")
for i, problem in enumerate(problems):
print(f" {i+1}. {problem}")
print("\n 💡 SOLUTIONS:")
for i, solution in enumerate(solutions):
print(f" {i+1}. {solution}")
else:
print(" ✅ Aucun problème technique identifié")
print(" 📋 Le problème est peut-être dans l'expérience utilisateur")
print("\n=== Fin du diagnostic ===")
if __name__ == '__main__':
test_ui_interaction()

View File

@@ -1,95 +0,0 @@
# Tests Unitaires
Ce dossier contient les tests unitaires pour l'application de gestion scolaire.
## Structure des tests
```
tests/
├── __init__.py
├── conftest.py # Configuration globale des tests
├── test_app.py # Tests de l'application Flask
├── test_models.py # Tests des modèles SQLAlchemy
├── test_forms.py # Tests des formulaires WTForms
├── test_services.py # Tests des services métier
├── test_routes_assessments.py # Tests des routes d'évaluations
└── test_utils.py # Tests des utilitaires
```
## Exécution des tests
### Avec uv (recommandé)
```bash
# Installer les dépendances de test
uv sync
# Exécuter tous les tests
uv run pytest tests/ -v
# Exécuter avec couverture de code
uv run pytest tests/ --cov=. --cov-report=html
# Exécuter des tests spécifiques
uv run pytest tests/test_models.py -v
uv run pytest tests/test_models.py::TestClassGroup -v
```
### Avec le script personnalisé
```bash
# Tous les tests
uv run python run_tests.py
# Avec rapport de couverture
uv run python run_tests.py --coverage
# Tests d'un fichier spécifique
uv run python run_tests.py test_models.py
# Mode silencieux
uv run python run_tests.py --quiet
```
## Configuration
Les tests utilisent:
- **pytest** comme framework de test
- **pytest-flask** pour l'intégration Flask
- **pytest-cov** pour la couverture de code
- **SQLite en mémoire** pour les tests de base de données
## Couverture des tests
Les tests couvrent:
- ✅ Modèles SQLAlchemy (création, validation, relations)
- ✅ Configuration de l'application Flask
- ✅ Services métier (AssessmentService)
- ✅ Utilitaires (validation, gestion d'erreurs)
- ✅ Formulaires WTForms (validation)
- ✅ Routes principales (responses HTTP)
## Bonnes pratiques
1. **Isolation**: Chaque test utilise une base de données temporaire
2. **Fixtures**: Configuration partagée dans `conftest.py`
3. **Nommage**: Tests préfixés par `test_`
4. **Organisation**: Tests groupés par classe selon la fonctionnalité
5. **Assertions**: Vérifications claires et spécifiques
## Ajout de nouveaux tests
Pour ajouter de nouveaux tests:
1. Créer un fichier `test_<module>.py`
2. Importer les fixtures nécessaires
3. OU utiliser les fixtures existantes (`app`, `client`)
4. Suivre la convention de nommage
Exemple:
```python
def test_my_function(app):
with app.app_context():
# Votre test ici
assert True
```