import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// Configuration globale pour les tests /// /// Cette classe configure l'environnement de test pour /// garantir des conditions cohérentes et reproductibles. class TestConfig { static bool _initialized = false; /// Initialise l'environnement de test static Future initialize() async { if (_initialized) return; TestWidgetsFlutterBinding.ensureInitialized(); // Configuration des SharedPreferences pour les tests SharedPreferences.setMockInitialValues({}); // Configuration des canaux de méthodes pour les tests _setupMethodChannels(); // Configuration des polices pour les tests de widgets _setupFonts(); _initialized = true; } /// Configure les canaux de méthodes mockés static void _setupMethodChannels() { // Canal pour les permissions const MethodChannel('flutter.baseflow.com/permissions/methods') .setMockMethodCallHandler((MethodCall methodCall) async { switch (methodCall.method) { case 'checkPermissionStatus': return 1; // PermissionStatus.granted case 'requestPermissions': return {0: 1}; // Permission granted default: return null; } }); // Canal pour la géolocalisation const MethodChannel('flutter.baseflow.com/geolocator') .setMockMethodCallHandler((MethodCall methodCall) async { switch (methodCall.method) { case 'getCurrentPosition': return { 'latitude': 5.3600, 'longitude': -4.0083, 'timestamp': DateTime.now().millisecondsSinceEpoch, 'accuracy': 10.0, 'altitude': 0.0, 'heading': 0.0, 'speed': 0.0, 'speedAccuracy': 0.0, }; case 'getLocationAccuracy': return 1; // LocationAccuracy.best default: return null; } }); // Canal pour le partage de fichiers const MethodChannel('plugins.flutter.io/share') .setMockMethodCallHandler((MethodCall methodCall) async { switch (methodCall.method) { case 'share': return null; // Succès silencieux default: return null; } }); // Canal pour l'ouverture d'URLs const MethodChannel('plugins.flutter.io/url_launcher') .setMockMethodCallHandler((MethodCall methodCall) async { switch (methodCall.method) { case 'launch': return true; // URL ouverte avec succès case 'canLaunch': return true; // URL peut être ouverte default: return null; } }); // Canal pour la sélection de fichiers const MethodChannel('miguelruivo.flutter.plugins.filepicker') .setMockMethodCallHandler((MethodCall methodCall) async { switch (methodCall.method) { case 'any': return { 'files': [ { 'name': 'test_document.pdf', 'path': '/mock/path/test_document.pdf', 'size': 1024000, 'bytes': null, } ] }; default: return null; } }); } /// Configure les polices pour les tests de widgets static void _setupFonts() { // Chargement des polices Material Design final binding = TestWidgetsFlutterBinding.ensureInitialized(); binding.defaultBinaryMessenger.setMockDecodedMessageHandler( const StandardMethodCodec(), (dynamic message) async { if (message is Map && message['method'] == 'SystemChrome.setApplicationSwitcherDescription') { return null; } return null; }, ); } /// Nettoie l'environnement de test après chaque test static Future cleanup() async { // Réinitialiser les SharedPreferences final prefs = await SharedPreferences.getInstance(); await prefs.clear(); // Nettoyer les canaux de méthodes _clearMethodChannels(); } /// Nettoie les canaux de méthodes static void _clearMethodChannels() { const MethodChannel('flutter.baseflow.com/permissions/methods') .setMockMethodCallHandler(null); const MethodChannel('flutter.baseflow.com/geolocator') .setMockMethodCallHandler(null); const MethodChannel('plugins.flutter.io/share') .setMockMethodCallHandler(null); const MethodChannel('plugins.flutter.io/url_launcher') .setMockMethodCallHandler(null); const MethodChannel('miguelruivo.flutter.plugins.filepicker') .setMockMethodCallHandler(null); } } /// Classe utilitaire pour les données de test class TestData { /// Données de test pour une demande d'aide static Map get demandeAideJson => { 'id': 'demande-test-123', 'numeroReference': 'REF-TEST-001', 'titre': 'Test Aide Médicale', 'description': 'Description de test pour aide médicale', 'typeAide': 'AIDE_FINANCIERE_MEDICALE', 'statut': 'BROUILLON', 'priorite': 'NORMALE', 'estUrgente': false, 'montantDemande': 100000.0, 'dateCreation': '2024-01-15T10:00:00Z', 'dateModification': '2024-01-15T10:00:00Z', 'organisationId': 'org-test', 'demandeurId': 'user-test', 'nomDemandeur': 'Test User', 'emailDemandeur': 'test@example.com', 'telephoneDemandeur': '+225123456789', 'beneficiaires': [], 'evaluations': [], 'commentairesInternes': [], 'historiqueStatuts': [], 'piecesJustificatives': [], 'tags': ['test'], 'metadonnees': {}, }; /// Données de test pour une proposition d'aide static Map get propositionAideJson => { 'id': 'proposition-test-123', 'titre': 'Test Proposition Aide', 'description': 'Description de test pour proposition', 'typeAide': 'AIDE_FINANCIERE_MEDICALE', 'statut': 'ACTIVE', 'montantMaximum': 200000.0, 'dateCreation': '2024-01-15T10:00:00Z', 'organisationId': 'org-test', 'proposantId': 'proposant-test', 'nomProposant': 'Test Proposant', 'emailProposant': 'proposant@example.com', 'telephoneProposant': '+225987654321', 'capacites': [], 'disponibilites': [], 'criteres': [], 'statistiques': {}, 'metadonnees': {}, }; /// Données de test pour une évaluation static Map get evaluationAideJson => { 'id': 'evaluation-test-123', 'demandeId': 'demande-test-123', 'evaluateurId': 'evaluateur-test', 'nomEvaluateur': 'Test Evaluateur', 'typeEvaluateur': 'ADMINISTRATEUR', 'dateEvaluation': '2024-01-16T10:00:00Z', 'noteGlobale': 4.0, 'criteres': { 'urgence': 4.0, 'legitimite': 4.0, 'faisabilite': 4.0, 'impact': 4.0, }, 'decision': 'APPROUVE', 'commentaires': 'Évaluation de test', 'recommandations': 'Recommandations de test', 'piecesJustificativesValidees': true, 'signalements': [], 'metadonnees': {}, }; } /// Classe utilitaire pour les assertions personnalisées class TestAssertions { /// Vérifie qu'une demande d'aide a les propriétés attendues static void assertDemandeAideValid(dynamic demande) { expect(demande.id, isNotEmpty); expect(demande.titre, isNotEmpty); expect(demande.description, isNotEmpty); expect(demande.typeAide, isNotNull); expect(demande.statut, isNotNull); expect(demande.priorite, isNotNull); expect(demande.dateCreation, isNotNull); expect(demande.organisationId, isNotEmpty); expect(demande.demandeurId, isNotEmpty); expect(demande.nomDemandeur, isNotEmpty); expect(demande.emailDemandeur, isNotEmpty); } /// Vérifie qu'une proposition d'aide a les propriétés attendues static void assertPropositionAideValid(dynamic proposition) { expect(proposition.id, isNotEmpty); expect(proposition.titre, isNotEmpty); expect(proposition.description, isNotEmpty); expect(proposition.typeAide, isNotNull); expect(proposition.statut, isNotNull); expect(proposition.dateCreation, isNotNull); expect(proposition.organisationId, isNotEmpty); expect(proposition.proposantId, isNotEmpty); expect(proposition.nomProposant, isNotEmpty); } /// Vérifie qu'une évaluation a les propriétés attendues static void assertEvaluationValid(dynamic evaluation) { expect(evaluation.id, isNotEmpty); expect(evaluation.demandeId, isNotEmpty); expect(evaluation.evaluateurId, isNotEmpty); expect(evaluation.nomEvaluateur, isNotEmpty); expect(evaluation.typeEvaluateur, isNotNull); expect(evaluation.dateEvaluation, isNotNull); expect(evaluation.noteGlobale, greaterThanOrEqualTo(0.0)); expect(evaluation.noteGlobale, lessThanOrEqualTo(5.0)); expect(evaluation.decision, isNotNull); } } /// Classe utilitaire pour les mocks class TestMocks { /// Crée un mock de réponse HTTP réussie static Map createSuccessResponse(dynamic data) { return { 'success': true, 'data': data, 'message': 'Opération réussie', 'timestamp': DateTime.now().toIso8601String(), }; } /// Crée un mock de réponse HTTP d'erreur static Map createErrorResponse(String message, {int code = 500}) { return { 'success': false, 'error': { 'code': code, 'message': message, 'details': null, }, 'timestamp': DateTime.now().toIso8601String(), }; } /// Crée un mock de réponse paginée static Map createPagedResponse(List content, { int page = 0, int size = 20, int totalElements = 0, int totalPages = 0, }) { return { 'content': content, 'page': { 'number': page, 'size': size, 'totalElements': totalElements ?? content.length, 'totalPages': totalPages ?? ((totalElements ?? content.length) / size).ceil(), }, 'first': page == 0, 'last': page >= (totalPages - 1), 'empty': content.isEmpty, }; } }