clean: remove tests
This commit is contained in:
@@ -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
|
||||
```
|
||||
106
tests/test_grading_validation.py
Normal file
106
tests/test_grading_validation.py
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test final pour valider que le système de configuration des échelles
|
||||
fonctionne correctement de bout en bout.
|
||||
"""
|
||||
|
||||
from app import create_app
|
||||
from app_config import config_manager
|
||||
|
||||
def test_final_validation():
|
||||
"""Test final de validation du système."""
|
||||
app = create_app('development')
|
||||
|
||||
with app.app_context():
|
||||
print("=== VALIDATION FINALE : Système de configuration des échelles ===\n")
|
||||
|
||||
# 1. Test des modifications via l'interface de configuration
|
||||
print("1. Test des modifications via config_manager:")
|
||||
|
||||
# Modifier le label de la valeur '1'
|
||||
success = config_manager.update_scale_value('1', 'EN APPRENTISSAGE', '#ff9900', True)
|
||||
print(f" Modification '1' → 'EN APPRENTISSAGE': {success}")
|
||||
|
||||
# Vérifier que la modification est persistée
|
||||
updated_values = config_manager.get_competence_scale_values()
|
||||
print(f" Nouveau label pour '1': '{updated_values['1']['label']}'")
|
||||
print(f" Nouvelle couleur pour '1': '{updated_values['1']['color']}'")
|
||||
|
||||
# 2. Test d'affichage dynamique
|
||||
print("\n2. Test d'affichage dynamique:")
|
||||
|
||||
display_info = config_manager.get_display_info('1', 'score')
|
||||
print(f" get_display_info('1', 'score'): {display_info}")
|
||||
|
||||
# 3. Test avec l'interface de notation
|
||||
print("\n3. Test d'intégration avec l'interface de notation:")
|
||||
|
||||
with app.test_client() as client:
|
||||
# Accéder à une page de notation
|
||||
response = client.get('/assessments/1/grading')
|
||||
|
||||
if response.status_code == 200:
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Vérifier que les labels modifiés apparaissent
|
||||
if 'EN APPRENTISSAGE' in content:
|
||||
print(" ✅ Label 'EN APPRENTISSAGE' trouvé dans l'interface de notation")
|
||||
else:
|
||||
print(" ❌ Label 'EN APPRENTISSAGE' non trouvé dans l'interface")
|
||||
|
||||
if 'SUPER ACQUIS' in content:
|
||||
print(" ✅ Label 'SUPER ACQUIS' trouvé dans l'interface de notation")
|
||||
else:
|
||||
print(" ❌ Label 'SUPER ACQUIS' non trouvé dans l'interface")
|
||||
else:
|
||||
print(f" ❌ Erreur d'accès à l'interface de notation: {response.status_code}")
|
||||
|
||||
# 4. Test de la page de configuration
|
||||
print("\n4. Test de la page de configuration:")
|
||||
|
||||
with app.test_client() as client:
|
||||
response = client.get('/config/scale')
|
||||
|
||||
if response.status_code == 200:
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
if 'EN APPRENTISSAGE' in content:
|
||||
print(" ✅ Label 'EN APPRENTISSAGE' trouvé dans la page de configuration")
|
||||
else:
|
||||
print(" ❌ Label 'EN APPRENTISSAGE' non trouvé dans la page de configuration")
|
||||
else:
|
||||
print(f" ❌ Erreur d'accès à la page de configuration: {response.status_code}")
|
||||
|
||||
# 5. Test de cohérence finale
|
||||
print("\n5. Test de cohérence finale:")
|
||||
|
||||
all_consistent = True
|
||||
scale_values = config_manager.get_competence_scale_values()
|
||||
|
||||
for value in ['0', '1', '2', '3']:
|
||||
if value in scale_values:
|
||||
db_label = scale_values[value]['label']
|
||||
display_info = config_manager.get_display_info(value, 'score')
|
||||
display_label = display_info['label']
|
||||
|
||||
if db_label == display_label:
|
||||
print(f" ✅ Cohérence pour '{value}': '{db_label}'")
|
||||
else:
|
||||
print(f" ❌ Incohérence pour '{value}': DB='{db_label}' vs Display='{display_label}'")
|
||||
all_consistent = False
|
||||
|
||||
# 6. Résultat final
|
||||
print("\n6. RÉSULTAT FINAL:")
|
||||
|
||||
if all_consistent:
|
||||
print(" 🎉 SUCCÈS : Le système de configuration des échelles fonctionne parfaitement !")
|
||||
print(" 📋 Les modifications apportées dans la page config/scale sont maintenant")
|
||||
print(" correctement prises en compte dans toute l'application.")
|
||||
print(" ✅ Problème de synchronisation des labels : RÉSOLU")
|
||||
else:
|
||||
print(" ⚠️ Certaines incohérences subsistent")
|
||||
|
||||
print("\n=== Fin de la validation ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_final_validation()
|
||||
167
tests/test_grading_validation_extended.py
Normal file
167
tests/test_grading_validation_extended.py
Normal file
@@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test pour vérifier que la validation stricte fonctionne correctement
|
||||
et accepte les nombres à virgule.
|
||||
"""
|
||||
|
||||
from app import create_app
|
||||
from app_config import config_manager
|
||||
from models import db, Grade
|
||||
import re
|
||||
|
||||
def test_strict_validation():
|
||||
"""Test de la validation stricte."""
|
||||
app = create_app('development')
|
||||
|
||||
with app.app_context():
|
||||
print("=== TEST : Validation stricte avec nombres décimaux ===\n")
|
||||
|
||||
# 1. Test de la fonction JavaScript générée
|
||||
print("1. Vérification de la fonction validateGradeValue JavaScript:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Vérifier que la validation stricte est présente
|
||||
if '/^[0-9]+([.,][0-9]+)?$/.test(trimmedValue)' in content:
|
||||
print(" ✅ Validation stricte avec regex présente")
|
||||
else:
|
||||
print(" ❌ Validation stricte manquante")
|
||||
|
||||
# Vérifier la conversion virgule -> point
|
||||
if "trimmedValue.replace(',', '.')" in content:
|
||||
print(" ✅ Conversion virgule -> point présente")
|
||||
else:
|
||||
print(" ❌ Conversion virgule -> point manquante")
|
||||
|
||||
# Vérifier les messages de validation
|
||||
if 'showValidationMessage(' in content:
|
||||
print(" ✅ Messages de validation présents")
|
||||
else:
|
||||
print(" ❌ Messages de validation manquants")
|
||||
print()
|
||||
|
||||
# 2. Test de validation côté serveur
|
||||
print("2. Test de validation côté serveur:")
|
||||
|
||||
test_cases = [
|
||||
# Valeurs valides
|
||||
('15', 'notes', True, 'Nombre entier'),
|
||||
('15.5', 'notes', True, 'Nombre décimal avec point'),
|
||||
('4,5', 'notes', True, 'Nombre décimal avec virgule (devrait être accepté côté serveur)'),
|
||||
('0', 'notes', True, 'Zéro'),
|
||||
('20', 'notes', True, 'Note maximale'),
|
||||
('.', 'notes', True, 'Valeur spéciale point'),
|
||||
('d', 'notes', True, 'Valeur spéciale d'),
|
||||
|
||||
# Valeurs invalides
|
||||
('abc', 'notes', False, 'Texte non numérique'),
|
||||
('25', 'notes', False, 'Nombre supérieur au maximum'),
|
||||
('-5', 'notes', False, 'Nombre négatif'),
|
||||
('15.5.2', 'notes', False, 'Format invalide'),
|
||||
('15abc', 'notes', False, 'Nombre avec lettres'),
|
||||
('', 'notes', True, 'Valeur vide (acceptée)'),
|
||||
|
||||
# Scores
|
||||
('0', 'score', True, 'Score 0'),
|
||||
('3', 'score', True, 'Score 3'),
|
||||
('4', 'score', False, 'Score invalide'),
|
||||
]
|
||||
|
||||
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()
|
||||
|
||||
# 3. Test de soumission avec valeurs strictes
|
||||
print("3. Test de soumission avec validation stricte:")
|
||||
|
||||
# Nettoyer les données existantes
|
||||
Grade.query.filter_by(student_id=2).delete()
|
||||
db.session.commit()
|
||||
|
||||
# Test avec différents types de valeurs
|
||||
test_data = {
|
||||
'grade_2_1': '15,5', # Nombre à virgule
|
||||
'grade_2_2': '.', # Valeur spéciale
|
||||
'grade_2_3': '18.0', # Nombre à point
|
||||
}
|
||||
|
||||
with app.test_client() as client:
|
||||
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(" ✅ Valeurs acceptées par le serveur")
|
||||
|
||||
# Vérifier les valeurs sauvées
|
||||
grades = Grade.query.filter_by(student_id=2).all()
|
||||
print(f" Grades sauvés: {len(grades)}")
|
||||
|
||||
for grade in grades:
|
||||
print(f" Sauvé: '{grade.value}'")
|
||||
else:
|
||||
print(" ❌ Erreur lors de la soumission")
|
||||
print()
|
||||
|
||||
# 4. Test des cas d'erreur
|
||||
print("4. Test des cas d'erreur:")
|
||||
|
||||
error_cases = {
|
||||
'grade_3_1': 'abc123', # Texte invalide
|
||||
'grade_3_2': '25', # Nombre trop grand
|
||||
'grade_3_3': '-5', # Nombre négatif
|
||||
}
|
||||
|
||||
with app.test_client() as client:
|
||||
print(f" Données d'erreur: {error_cases}")
|
||||
|
||||
response = client.post('/assessments/1/grading/save',
|
||||
data=error_cases,
|
||||
follow_redirects=True)
|
||||
|
||||
print(f" Soumission: statut {response.status_code}")
|
||||
|
||||
# Vérifier qu'il y a des messages d'erreur
|
||||
if response.status_code == 200:
|
||||
content = response.get_data(as_text=True)
|
||||
if 'Valeur invalide' in content or 'warning' in content:
|
||||
print(" ✅ Messages d'erreur présents")
|
||||
else:
|
||||
print(" 📋 Pas de messages d'erreur visibles (peut être normal)")
|
||||
print()
|
||||
|
||||
# 5. Résumé des améliorations
|
||||
print("5. RÉSUMÉ DES AMÉLIORATIONS DE VALIDATION:")
|
||||
|
||||
improvements = [
|
||||
"✅ Validation stricte avec regex /^[0-9]+([.,][0-9]+)?$/",
|
||||
"✅ Conversion automatique virgule -> point (4,5 → 4.5)",
|
||||
"✅ Feedback visuel immédiat (rouge/vert)",
|
||||
"✅ Messages de validation contextuels",
|
||||
"✅ Validation des plages de valeurs (0 à max_points)",
|
||||
"✅ Support des valeurs spéciales configurées",
|
||||
"✅ Validation côté client ET serveur",
|
||||
]
|
||||
|
||||
for improvement in improvements:
|
||||
print(f" {improvement}")
|
||||
|
||||
print("\n 🎯 VALIDATION STRICTE IMPLÉMENTÉE !")
|
||||
print(" 📋 Comportements validés:")
|
||||
print(" - Seuls les nombres et valeurs spéciales sont acceptés")
|
||||
print(" - 4,5 est automatiquement converti en 4.5")
|
||||
print(" - Messages d'erreur clairs pour l'utilisateur")
|
||||
print(" - Feedback visuel immédiat (couleurs)")
|
||||
print(" - Validation des plages de valeurs")
|
||||
|
||||
print("\n=== Fin du test ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_strict_validation()
|
||||
190
tests/test_grading_validation_strict.py
Normal file
190
tests/test_grading_validation_strict.py
Normal file
@@ -0,0 +1,190 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test final pour valider que la validation stricte fonctionne
|
||||
parfaitement avec les max_points et tous les cas d'usage.
|
||||
"""
|
||||
|
||||
from app import create_app
|
||||
from app_config import config_manager
|
||||
from models import db, Grade, GradingElement
|
||||
import re
|
||||
|
||||
def test_final_validation_stricte():
|
||||
"""Test final de la validation stricte."""
|
||||
app = create_app('development')
|
||||
|
||||
with app.app_context():
|
||||
print("=== TEST FINAL : Validation stricte parfaite ===\n")
|
||||
|
||||
# 1. Test avec max_points réels
|
||||
print("1. Test avec max_points réels:")
|
||||
|
||||
# Récupérer un élément de notation réel
|
||||
grading_element = GradingElement.query.filter_by(grading_type='notes').first()
|
||||
if grading_element:
|
||||
max_points = grading_element.max_points
|
||||
print(f" Élément testé: {grading_element.label} (max: {max_points} points)")
|
||||
|
||||
test_cases = [
|
||||
('4,5', True, 'Nombre à virgule dans la plage'),
|
||||
('15.5', True, 'Nombre à point dans la plage'),
|
||||
(str(max_points), True, 'Valeur maximale exacte'),
|
||||
(str(max_points + 1), False, 'Valeur supérieure au maximum'),
|
||||
('0', True, 'Zéro'),
|
||||
('.', True, 'Valeur spéciale'),
|
||||
('d', True, 'Valeur spéciale'),
|
||||
('abc', False, 'Texte invalide'),
|
||||
('-1', False, 'Valeur négative'),
|
||||
('', True, 'Valeur vide'),
|
||||
]
|
||||
|
||||
for value, expected, description in test_cases:
|
||||
is_valid = config_manager.validate_grade_value(value, 'notes', max_points)
|
||||
status = "✅" if is_valid == expected else "❌"
|
||||
print(f" {status} {description}: '{value}' → {is_valid} (attendu: {expected})")
|
||||
else:
|
||||
print(" ❌ Aucun élément de type 'notes' trouvé")
|
||||
print()
|
||||
|
||||
# 2. Test de soumission complète avec validation stricte
|
||||
print("2. Test de soumission avec validation stricte:")
|
||||
|
||||
# Nettoyer les données de test
|
||||
Grade.query.filter_by(student_id=1).delete()
|
||||
db.session.commit()
|
||||
|
||||
# Tester avec des valeurs mixtes
|
||||
test_data = {
|
||||
'grade_1_1': '15,5', # Virgule -> doit être converti
|
||||
'grade_1_2': '2', # Score valide
|
||||
'grade_1_3': '.', # Valeur spéciale
|
||||
}
|
||||
|
||||
with app.test_client() as client:
|
||||
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(" ✅ Soumission acceptée")
|
||||
|
||||
# Vérifier les valeurs sauvées (surtout la conversion virgule->point)
|
||||
grades = Grade.query.filter_by(student_id=1).all()
|
||||
print(f" Grades sauvés: {len(grades)}")
|
||||
|
||||
for grade in grades:
|
||||
element = GradingElement.query.get(grade.grading_element_id)
|
||||
if element:
|
||||
print(f" {element.label}: '{grade.value}' (type: {element.grading_type})")
|
||||
|
||||
# Vérifier spécialement la conversion 15,5 -> 15.5
|
||||
if element.grading_type == 'notes' and '.' in grade.value:
|
||||
print(f" ✅ Conversion virgule->point réussie")
|
||||
else:
|
||||
print(" ❌ Erreur lors de la soumission")
|
||||
print()
|
||||
|
||||
# 3. Test des cas d'erreur avec validation stricte
|
||||
print("3. Test des cas d'erreur stricts:")
|
||||
|
||||
# Nettoyer
|
||||
Grade.query.filter_by(student_id=2).delete()
|
||||
db.session.commit()
|
||||
|
||||
# Tester avec des valeurs invalides
|
||||
error_cases = {
|
||||
'grade_2_1': 'abc123', # Texte avec chiffres
|
||||
'grade_2_2': '50', # Nombre trop grand (> max_points)
|
||||
'grade_2_3': '15.5.2', # Format invalide
|
||||
}
|
||||
|
||||
with app.test_client() as client:
|
||||
print(f" Données d'erreur: {error_cases}")
|
||||
|
||||
response = client.post('/assessments/1/grading/save',
|
||||
data=error_cases,
|
||||
follow_redirects=True)
|
||||
|
||||
print(f" Soumission: statut {response.status_code}")
|
||||
|
||||
# Vérifier qu'aucune valeur invalide n'a été sauvée
|
||||
invalid_grades = Grade.query.filter_by(student_id=2).all()
|
||||
print(f" Grades invalides sauvés: {len(invalid_grades)} (devrait être 0)")
|
||||
|
||||
if len(invalid_grades) == 0:
|
||||
print(" ✅ Validation stricte côté serveur fonctionne")
|
||||
else:
|
||||
print(" ❌ Des valeurs invalides ont été sauvées")
|
||||
for grade in invalid_grades:
|
||||
print(f" Sauvé incorrectement: '{grade.value}'")
|
||||
print()
|
||||
|
||||
# 4. Test de l'interface utilisateur
|
||||
print("4. Test de l'interface utilisateur:")
|
||||
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Vérifier que les champs sont de type text
|
||||
text_inputs = content.count('type="text"')
|
||||
number_inputs = content.count('type="number"')
|
||||
|
||||
print(f" Champs type='text': {text_inputs}")
|
||||
print(f" Champs type='number': {number_inputs}")
|
||||
|
||||
if number_inputs == 0:
|
||||
print(" ✅ Plus de champs type='number' qui bloquent les valeurs spéciales")
|
||||
else:
|
||||
print(" ❌ Il reste des champs type='number'")
|
||||
|
||||
# Vérifier la validation JavaScript
|
||||
js_validations = [
|
||||
"validateGradeValue(value, type, maxPoints)",
|
||||
"SPECIAL_VALUES_KEYS.includes(e.key)",
|
||||
"showValidationMessage(",
|
||||
"/^[0-9]+([.,][0-9]+)?$/.test(trimmedValue)"
|
||||
]
|
||||
|
||||
for validation in js_validations:
|
||||
if validation in content:
|
||||
print(f" ✅ {validation[:30]}... présent")
|
||||
else:
|
||||
print(f" ❌ {validation[:30]}... manquant")
|
||||
print()
|
||||
|
||||
# 5. Test de performance et UX
|
||||
print("5. Test de l'expérience utilisateur:")
|
||||
|
||||
features = [
|
||||
"✅ Conversion automatique virgule -> point (15,5 → 15.5)",
|
||||
"✅ Validation stricte avec regex (seuls nombres + valeurs spéciales)",
|
||||
"✅ Feedback visuel immédiat (rouge/vert)",
|
||||
"✅ Messages d'erreur contextuels",
|
||||
"✅ Validation des plages (0 à max_points)",
|
||||
"✅ Support complet des valeurs spéciales configurées",
|
||||
"✅ Validation côté client ET serveur synchronisées",
|
||||
"✅ Pas de champs type='number' qui bloquent la saisie",
|
||||
"✅ Placeholders dynamiques informatifs",
|
||||
]
|
||||
|
||||
for feature in features:
|
||||
print(f" {feature}")
|
||||
|
||||
print("\n 🎯 VALIDATION STRICTE PARFAITE !")
|
||||
print(" 📋 L'utilisateur peut maintenant:")
|
||||
print(" - Taper 4,5 et voir automatiquement 4.5")
|
||||
print(" - Recevoir des messages d'erreur clairs")
|
||||
print(" - Voir immédiatement si sa saisie est valide (couleurs)")
|
||||
print(" - Utiliser toutes les valeurs spéciales configurées")
|
||||
print(" - Bénéficier d'une validation cohérente client/serveur")
|
||||
print(" - Ne plus avoir de comportements bloquants")
|
||||
|
||||
print("\n=== Fin du test ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_final_validation_stricte()
|
||||
165
tests/test_special_values.py
Normal file
165
tests/test_special_values.py
Normal file
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test final pour valider que les valeurs spéciales fonctionnent
|
||||
correctement dans l'interface de notation.
|
||||
"""
|
||||
|
||||
from app import create_app
|
||||
from app_config import config_manager
|
||||
from models import db, Grade
|
||||
import re
|
||||
|
||||
def test_final_special_values():
|
||||
"""Test final des valeurs spéciales."""
|
||||
app = create_app('development')
|
||||
|
||||
with app.app_context():
|
||||
print("=== TEST FINAL : Valeurs spéciales fonctionnelles ===\n")
|
||||
|
||||
# 1. Vérifier la configuration
|
||||
print("1. Configuration des valeurs spéciales:")
|
||||
scale_values = config_manager.get_competence_scale_values()
|
||||
special_values = ['.', 'd']
|
||||
|
||||
for value in special_values:
|
||||
if value in scale_values:
|
||||
config = scale_values[value]
|
||||
print(f" ✅ '{value}': {config['label']} (couleur: {config['color']})")
|
||||
else:
|
||||
print(f" ❌ '{value}': NON CONFIGURÉE")
|
||||
print()
|
||||
|
||||
# 2. Vérifier la génération JavaScript
|
||||
print("2. Configuration JavaScript:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
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 les valeurs sont présentes
|
||||
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")
|
||||
else:
|
||||
print(" ❌ Configuration JavaScript non trouvée")
|
||||
print()
|
||||
|
||||
# 3. Vérifier les options SELECT
|
||||
print("3. Options des champs SELECT (type 'score'):")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Extraire toutes les options
|
||||
option_pattern = r'<option value="([^"]*)"[^>]*>([^<]*)</option>'
|
||||
options = re.findall(option_pattern, content)
|
||||
|
||||
special_options = [(v, t) for v, t in options if v in special_values]
|
||||
print(f" Options spéciales trouvées: {len(special_options)}")
|
||||
|
||||
for value, text in special_options:
|
||||
print(f" ✅ <option value=\"{value}\">{text}</option>")
|
||||
print()
|
||||
|
||||
# 4. Test de soumission complète
|
||||
print("4. Test de soumission avec valeurs spéciales:")
|
||||
|
||||
# Nettoyer les données existantes pour ce test
|
||||
Grade.query.filter_by(student_id=1).delete()
|
||||
db.session.commit()
|
||||
|
||||
with app.test_client() as client:
|
||||
# Test avec différentes valeurs spéciales
|
||||
test_data = {
|
||||
'grade_1_1': '.', # Champ notes avec "pas de réponse"
|
||||
'grade_1_2': 'd', # Champ score avec "dispensé"
|
||||
'grade_1_3': '2', # Valeur normale pour contrôle
|
||||
}
|
||||
|
||||
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: # Redirection = succès
|
||||
print(" ✅ Soumission acceptée")
|
||||
|
||||
# Vérifier que les valeurs ont été sauvées
|
||||
grades = Grade.query.filter_by(student_id=1).all()
|
||||
print(f" Grades sauvés: {len(grades)}")
|
||||
|
||||
for grade in grades:
|
||||
display_info = config_manager.get_display_info(grade.value, 'score')
|
||||
print(f" Élément {grade.grading_element_id}: '{grade.value}' → {display_info['label']}")
|
||||
else:
|
||||
print(" ❌ Erreur lors de la soumission")
|
||||
print()
|
||||
|
||||
# 5. Test de l'affichage après sauvegarde
|
||||
print("5. Test d'affichage après sauvegarde:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
|
||||
if response.status_code == 200:
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Vérifier que les valeurs spéciales sont présélectionnées
|
||||
for value in special_values:
|
||||
if f'selected>{value}' in content or f'value="{value}"' in content:
|
||||
print(f" ✅ Valeur '{value}' correctement affichée/sélectionnée")
|
||||
else:
|
||||
print(f" 📋 Valeur '{value}' peut ne pas être visible (normal si pas dans ce champ)")
|
||||
print()
|
||||
|
||||
# 6. Résumé final
|
||||
print("6. RÉSUMÉ FINAL:")
|
||||
|
||||
# Vérification complète
|
||||
checks = []
|
||||
|
||||
# Config de base
|
||||
all_special_configured = all(v in scale_values for v in special_values)
|
||||
checks.append(("Valeurs spéciales configurées", all_special_configured))
|
||||
|
||||
# JavaScript
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
content = response.get_data(as_text=True)
|
||||
js_has_special = all(f"'{v}'" in content for v in special_values)
|
||||
checks.append(("JavaScript contient valeurs spéciales", js_has_special))
|
||||
|
||||
# Options HTML
|
||||
option_pattern = r'<option value="([^"]*)"'
|
||||
html_options = re.findall(option_pattern, content)
|
||||
html_has_special = all(v in html_options for v in special_values)
|
||||
checks.append(("HTML contient options spéciales", html_has_special))
|
||||
|
||||
# Affichage des résultats
|
||||
all_passed = True
|
||||
for check_name, passed in checks:
|
||||
status = "✅" if passed else "❌"
|
||||
print(f" {status} {check_name}")
|
||||
if not passed:
|
||||
all_passed = False
|
||||
|
||||
if all_passed:
|
||||
print("\n 🎉 SUCCÈS : Les valeurs spéciales sont maintenant fonctionnelles !")
|
||||
print(" 📋 L'utilisateur peut:")
|
||||
print(" - Sélectionner '.' et 'd' dans les listes déroulantes (type score)")
|
||||
print(" - Taper '.' et 'd' dans les champs numériques (type notes)")
|
||||
print(" - Utiliser les raccourcis clavier pour saisir rapidement")
|
||||
else:
|
||||
print("\n ⚠️ Certains problèmes subsistent")
|
||||
|
||||
print("\n=== Fin du test ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_final_special_values()
|
||||
143
tests/test_special_values_input.py
Normal file
143
tests/test_special_values_input.py
Normal file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test pour diagnostiquer le problème de saisie des valeurs spéciales
|
||||
dans la page de notation.
|
||||
"""
|
||||
|
||||
from app import create_app
|
||||
from app_config import config_manager
|
||||
|
||||
def test_special_values_input():
|
||||
"""Test des valeurs spéciales dans l'interface de notation."""
|
||||
app = create_app('development')
|
||||
|
||||
with app.app_context():
|
||||
print("=== DIAGNOSTIC : Problème saisie valeurs spéciales ===\n")
|
||||
|
||||
# 1. Vérifier les valeurs spéciales configurées
|
||||
print("1. Valeurs spéciales configurées:")
|
||||
scale_values = config_manager.get_competence_scale_values()
|
||||
special_values = ['.', 'd', 'a']
|
||||
|
||||
for value in special_values:
|
||||
if value in scale_values:
|
||||
config = scale_values[value]
|
||||
print(f" '{value}': {config['label']} (couleur: {config['color']})")
|
||||
else:
|
||||
print(f" '{value}': NON CONFIGURÉE")
|
||||
print()
|
||||
|
||||
# 2. Tester l'accès à une page de notation
|
||||
print("2. Test d'accès à la page de notation:")
|
||||
with app.test_client() as client:
|
||||
response = client.get('/assessments/1/grading')
|
||||
print(f" Statut: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
content = response.get_data(as_text=True)
|
||||
|
||||
# Vérifier la présence des valeurs spéciales dans le HTML
|
||||
print(" Vérification des valeurs spéciales dans le HTML:")
|
||||
for value in special_values:
|
||||
if value in scale_values:
|
||||
label = scale_values[value]['label']
|
||||
if f"value=\"{value}\"" in content:
|
||||
print(f" ✅ '{value}' trouvé dans le HTML")
|
||||
else:
|
||||
print(f" ❌ '{value}' NON trouvé dans le HTML")
|
||||
|
||||
if label in content:
|
||||
print(f" ✅ Label '{label}' trouvé dans le HTML")
|
||||
else:
|
||||
print(f" ❌ Label '{label}' NON trouvé dans le HTML")
|
||||
else:
|
||||
print(f" ❌ Erreur d'accès: {response.status_code}")
|
||||
print()
|
||||
|
||||
# 3. Analyser le template pour les valeurs spéciales
|
||||
print("3. Analyse du template assessment_grading.html:")
|
||||
try:
|
||||
with open('templates/assessment_grading.html', 'r', encoding='utf-8') as f:
|
||||
template_content = f.read()
|
||||
|
||||
# Chercher les patterns pour les valeurs spéciales
|
||||
import re
|
||||
|
||||
# Pattern pour les valeurs spéciales hardcodées
|
||||
hardcoded_pattern = r"for special_value in \['\.', 'd', 'a'\]"
|
||||
if re.search(hardcoded_pattern, template_content):
|
||||
print(" ✅ Pattern des valeurs spéciales trouvé")
|
||||
else:
|
||||
print(" ❌ Pattern des valeurs spéciales NON trouvé")
|
||||
|
||||
# Pattern pour la vérification si la valeur existe dans scale_values
|
||||
check_pattern = r"if special_value in scale_values"
|
||||
if re.search(check_pattern, template_content):
|
||||
print(" ✅ Vérification 'if special_value in scale_values' trouvée")
|
||||
else:
|
||||
print(" ❌ Vérification 'if special_value in scale_values' NON trouvée")
|
||||
|
||||
# Pattern pour l'affichage des valeurs spéciales
|
||||
display_pattern = r"config_manager\.get_display_info\(special_value, 'score'\)"
|
||||
if re.search(display_pattern, template_content):
|
||||
print(" ✅ Utilisation de get_display_info pour valeurs spéciales trouvée")
|
||||
else:
|
||||
print(" ❌ Utilisation de get_display_info pour valeurs spéciales NON trouvée")
|
||||
|
||||
except FileNotFoundError:
|
||||
print(" ❌ Fichier template non trouvé")
|
||||
print()
|
||||
|
||||
# 4. Test de validation côté serveur
|
||||
print("4. Test de validation côté serveur:")
|
||||
|
||||
# Tester validate_grade_value pour valeurs spéciales
|
||||
test_values = ['.', 'd', 'a', '0', '1', '2', '3', 'invalid']
|
||||
|
||||
for value in test_values:
|
||||
is_valid_score = config_manager.validate_grade_value(value, 'score')
|
||||
is_valid_notes = config_manager.validate_grade_value(value, 'notes')
|
||||
print(f" '{value}': score={is_valid_score}, notes={is_valid_notes}")
|
||||
print()
|
||||
|
||||
# 5. Test de soumission simulée avec valeurs spéciales
|
||||
print("5. Test de soumission avec valeurs spéciales:")
|
||||
with app.test_client() as client:
|
||||
# Simuler une soumission avec des valeurs spéciales
|
||||
form_data = {
|
||||
'grade_1_1': '.', # Valeur spéciale "pas de réponse"
|
||||
'grade_1_2': 'd', # Valeur spéciale "dispensé"
|
||||
'grade_1_3': '2', # Valeur normale
|
||||
}
|
||||
|
||||
response = client.post('/assessments/1/grading/save', data=form_data, follow_redirects=False)
|
||||
print(f" Soumission avec valeurs spéciales: {response.status_code}")
|
||||
|
||||
if response.status_code == 302: # Redirect après succès
|
||||
print(" ✅ Soumission acceptée (redirection)")
|
||||
elif response.status_code == 200:
|
||||
print(" ⚠️ Soumission retournée à la page (possibles erreurs)")
|
||||
else:
|
||||
print(f" ❌ Erreur lors de la soumission: {response.status_code}")
|
||||
print()
|
||||
|
||||
# 6. Diagnostic final
|
||||
print("6. DIAGNOSTIC FINAL:")
|
||||
|
||||
# Vérifier si toutes les valeurs spéciales sont bien configurées
|
||||
missing_special_values = []
|
||||
for value in special_values:
|
||||
if value not in scale_values:
|
||||
missing_special_values.append(value)
|
||||
|
||||
if missing_special_values:
|
||||
print(f" 🚨 PROBLÈME: Valeurs spéciales manquantes: {missing_special_values}")
|
||||
print(" 📋 SOLUTION: Ajouter ces valeurs via la page config/scale")
|
||||
else:
|
||||
print(" ✅ Toutes les valeurs spéciales sont configurées")
|
||||
print(" 📋 Vérifier si le problème vient du JavaScript ou de la validation")
|
||||
|
||||
print("\n=== Fin du diagnostic ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_special_values_input()
|
||||
Reference in New Issue
Block a user