Refactoring

This commit is contained in:
DahoudG
2025-09-17 17:54:06 +00:00
parent 12d514d866
commit 63fe107f98
165 changed files with 54220 additions and 276 deletions

View File

@@ -0,0 +1,441 @@
import 'package:bloc_test/bloc_test.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:unionflow_mobile_apps/core/error/failures.dart';
import 'package:unionflow_mobile_apps/features/solidarite/domain/entities/demande_aide.dart';
import 'package:unionflow_mobile_apps/features/solidarite/domain/usecases/gerer_demandes_aide_usecase.dart';
import 'package:unionflow_mobile_apps/features/solidarite/presentation/bloc/demandes_aide/demandes_aide_bloc.dart';
import 'package:unionflow_mobile_apps/features/solidarite/presentation/bloc/demandes_aide/demandes_aide_event.dart';
import 'package:unionflow_mobile_apps/features/solidarite/presentation/bloc/demandes_aide/demandes_aide_state.dart';
import 'demandes_aide_bloc_test.mocks.dart';
@GenerateMocks([
CreerDemandeAideUseCase,
MettreAJourDemandeAideUseCase,
ObtenirDemandeAideUseCase,
SoumettreDemandeAideUseCase,
EvaluerDemandeAideUseCase,
RechercherDemandesAideUseCase,
ObtenirDemandesUrgentesUseCase,
ObtenirMesDemandesUseCase,
ValiderDemandeAideUseCase,
CalculerPrioriteDemandeUseCase,
])
void main() {
group('DemandesAideBloc', () {
late DemandesAideBloc bloc;
late MockCreerDemandeAideUseCase mockCreerDemandeAideUseCase;
late MockMettreAJourDemandeAideUseCase mockMettreAJourDemandeAideUseCase;
late MockObtenirDemandeAideUseCase mockObtenirDemandeAideUseCase;
late MockSoumettreDemandeAideUseCase mockSoumettreDemandeAideUseCase;
late MockEvaluerDemandeAideUseCase mockEvaluerDemandeAideUseCase;
late MockRechercherDemandesAideUseCase mockRechercherDemandesAideUseCase;
late MockObtenirDemandesUrgentesUseCase mockObtenirDemandesUrgentesUseCase;
late MockObtenirMesDemandesUseCase mockObtenirMesDemandesUseCase;
late MockValiderDemandeAideUseCase mockValiderDemandeAideUseCase;
late MockCalculerPrioriteDemandeUseCase mockCalculerPrioriteDemandeUseCase;
setUp(() {
mockCreerDemandeAideUseCase = MockCreerDemandeAideUseCase();
mockMettreAJourDemandeAideUseCase = MockMettreAJourDemandeAideUseCase();
mockObtenirDemandeAideUseCase = MockObtenirDemandeAideUseCase();
mockSoumettreDemandeAideUseCase = MockSoumettreDemandeAideUseCase();
mockEvaluerDemandeAideUseCase = MockEvaluerDemandeAideUseCase();
mockRechercherDemandesAideUseCase = MockRechercherDemandesAideUseCase();
mockObtenirDemandesUrgentesUseCase = MockObtenirDemandesUrgentesUseCase();
mockObtenirMesDemandesUseCase = MockObtenirMesDemandesUseCase();
mockValiderDemandeAideUseCase = MockValiderDemandeAideUseCase();
mockCalculerPrioriteDemandeUseCase = MockCalculerPrioriteDemandeUseCase();
bloc = DemandesAideBloc(
creerDemandeAideUseCase: mockCreerDemandeAideUseCase,
mettreAJourDemandeAideUseCase: mockMettreAJourDemandeAideUseCase,
obtenirDemandeAideUseCase: mockObtenirDemandeAideUseCase,
soumettreDemandeAideUseCase: mockSoumettreDemandeAideUseCase,
evaluerDemandeAideUseCase: mockEvaluerDemandeAideUseCase,
rechercherDemandesAideUseCase: mockRechercherDemandesAideUseCase,
obtenirDemandesUrgentesUseCase: mockObtenirDemandesUrgentesUseCase,
obtenirMesDemandesUseCase: mockObtenirMesDemandesUseCase,
validerDemandeAideUseCase: mockValiderDemandeAideUseCase,
calculerPrioriteDemandeUseCase: mockCalculerPrioriteDemandeUseCase,
);
});
tearDown(() {
bloc.close();
});
test('état initial est DemandesAideInitial', () {
expect(bloc.state, equals(const DemandesAideInitial()));
});
group('ChargerDemandesAideEvent', () {
final tDemandes = [
_createTestDemandeAide('1', 'Demande 1'),
_createTestDemandeAide('2', 'Demande 2'),
];
blocTest<DemandesAideBloc, DemandesAideState>(
'émet [DemandesAideLoading, DemandesAideLoaded] quand les données sont chargées avec succès',
build: () {
when(mockRechercherDemandesAideUseCase(any))
.thenAnswer((_) async => Right(tDemandes));
return bloc;
},
act: (bloc) => bloc.add(const ChargerDemandesAideEvent()),
expect: () => [
const DemandesAideLoading(),
isA<DemandesAideLoaded>()
.having((state) => state.demandes, 'demandes', tDemandes)
.having((state) => state.demandesFiltrees, 'demandesFiltrees', tDemandes)
.having((state) => state.hasReachedMax, 'hasReachedMax', true)
.having((state) => state.currentPage, 'currentPage', 0)
.having((state) => state.totalElements, 'totalElements', 2),
],
verify: (_) {
verify(mockRechercherDemandesAideUseCase(
RechercherDemandesAideParams(
organisationId: null,
typeAide: null,
statut: null,
demandeurId: null,
urgente: null,
page: 0,
taille: 20,
),
));
},
);
blocTest<DemandesAideBloc, DemandesAideState>(
'émet [DemandesAideLoading, DemandesAideError] quand le chargement échoue',
build: () {
when(mockRechercherDemandesAideUseCase(any))
.thenAnswer((_) async => const Left(ServerFailure('Erreur serveur')));
return bloc;
},
act: (bloc) => bloc.add(const ChargerDemandesAideEvent()),
expect: () => [
const DemandesAideLoading(),
isA<DemandesAideError>()
.having((state) => state.message, 'message', 'Erreur serveur. Veuillez réessayer plus tard.')
.having((state) => state.isNetworkError, 'isNetworkError', false)
.having((state) => state.canRetry, 'canRetry', true),
],
);
blocTest<DemandesAideBloc, DemandesAideState>(
'émet [DemandesAideLoaded] avec isRefreshing=true quand forceRefresh=false et état déjà chargé',
build: () {
when(mockRechercherDemandesAideUseCase(any))
.thenAnswer((_) async => Right(tDemandes));
return bloc;
},
seed: () => DemandesAideLoaded(
demandes: const [],
demandesFiltrees: const [],
lastUpdated: DateTime.now(),
),
act: (bloc) => bloc.add(const ChargerDemandesAideEvent()),
expect: () => [
isA<DemandesAideLoaded>().having((state) => state.isRefreshing, 'isRefreshing', true),
isA<DemandesAideLoaded>()
.having((state) => state.demandes, 'demandes', tDemandes)
.having((state) => state.isRefreshing, 'isRefreshing', false),
],
);
});
group('CreerDemandeAideEvent', () {
final tDemande = _createTestDemandeAide('1', 'Nouvelle demande');
blocTest<DemandesAideBloc, DemandesAideState>(
'émet [DemandesAideLoading, DemandesAideOperationSuccess, DemandesAideLoading, DemandesAideLoaded] quand la création réussit',
build: () {
when(mockCreerDemandeAideUseCase(any))
.thenAnswer((_) async => Right(tDemande));
when(mockRechercherDemandesAideUseCase(any))
.thenAnswer((_) async => Right([tDemande]));
return bloc;
},
act: (bloc) => bloc.add(CreerDemandeAideEvent(demande: tDemande)),
expect: () => [
const DemandesAideLoading(),
isA<DemandesAideOperationSuccess>()
.having((state) => state.message, 'message', 'Demande d\'aide créée avec succès')
.having((state) => state.demande, 'demande', tDemande)
.having((state) => state.operation, 'operation', TypeOperationDemande.creation),
const DemandesAideLoading(),
isA<DemandesAideLoaded>(),
],
verify: (_) {
verify(mockCreerDemandeAideUseCase(CreerDemandeAideParams(demande: tDemande)));
},
);
blocTest<DemandesAideBloc, DemandesAideState>(
'émet [DemandesAideLoading, DemandesAideError] quand la création échoue',
build: () {
when(mockCreerDemandeAideUseCase(any))
.thenAnswer((_) async => const Left(ValidationFailure('Données invalides')));
return bloc;
},
act: (bloc) => bloc.add(CreerDemandeAideEvent(demande: tDemande)),
expect: () => [
const DemandesAideLoading(),
isA<DemandesAideError>()
.having((state) => state.message, 'message', 'Données invalides'),
],
);
});
group('FiltrerDemandesAideEvent', () {
final tDemandes = [
_createTestDemandeAide('1', 'Demande urgente', estUrgente: true),
_createTestDemandeAide('2', 'Demande normale', estUrgente: false),
];
blocTest<DemandesAideBloc, DemandesAideState>(
'filtre les demandes par urgence',
build: () => bloc,
seed: () => DemandesAideLoaded(
demandes: tDemandes,
demandesFiltrees: tDemandes,
lastUpdated: DateTime.now(),
),
act: (bloc) => bloc.add(const FiltrerDemandesAideEvent(urgente: true)),
expect: () => [
isA<DemandesAideLoaded>()
.having((state) => state.demandesFiltrees.length, 'demandesFiltrees.length', 1)
.having((state) => state.demandesFiltrees.first.estUrgente, 'estUrgente', true)
.having((state) => state.filtres.urgente, 'filtres.urgente', true),
],
);
blocTest<DemandesAideBloc, DemandesAideState>(
'filtre les demandes par mot-clé',
build: () => bloc,
seed: () => DemandesAideLoaded(
demandes: tDemandes,
demandesFiltrees: tDemandes,
lastUpdated: DateTime.now(),
),
act: (bloc) => bloc.add(const FiltrerDemandesAideEvent(motCle: 'urgente')),
expect: () => [
isA<DemandesAideLoaded>()
.having((state) => state.demandesFiltrees.length, 'demandesFiltrees.length', 1)
.having((state) => state.demandesFiltrees.first.titre, 'titre', 'Demande urgente')
.having((state) => state.filtres.motCle, 'filtres.motCle', 'urgente'),
],
);
});
group('TrierDemandesAideEvent', () {
final tDemandes = [
_createTestDemandeAide('1', 'B Demande', dateCreation: DateTime(2023, 1, 2)),
_createTestDemandeAide('2', 'A Demande', dateCreation: DateTime(2023, 1, 1)),
];
blocTest<DemandesAideBloc, DemandesAideState>(
'trie les demandes par titre croissant',
build: () => bloc,
seed: () => DemandesAideLoaded(
demandes: tDemandes,
demandesFiltrees: tDemandes,
lastUpdated: DateTime.now(),
),
act: (bloc) => bloc.add(const TrierDemandesAideEvent(
critere: TriDemandes.titre,
croissant: true,
)),
expect: () => [
isA<DemandesAideLoaded>()
.having((state) => state.demandesFiltrees.first.titre, 'premier titre', 'A Demande')
.having((state) => state.demandesFiltrees.last.titre, 'dernier titre', 'B Demande')
.having((state) => state.criterieTri, 'criterieTri', TriDemandes.titre)
.having((state) => state.triCroissant, 'triCroissant', true),
],
);
blocTest<DemandesAideBloc, DemandesAideState>(
'trie les demandes par date décroissant',
build: () => bloc,
seed: () => DemandesAideLoaded(
demandes: tDemandes,
demandesFiltrees: tDemandes,
lastUpdated: DateTime.now(),
),
act: (bloc) => bloc.add(const TrierDemandesAideEvent(
critere: TriDemandes.dateCreation,
croissant: false,
)),
expect: () => [
isA<DemandesAideLoaded>()
.having((state) => state.demandesFiltrees.first.dateCreation, 'première date', DateTime(2023, 1, 2))
.having((state) => state.demandesFiltrees.last.dateCreation, 'dernière date', DateTime(2023, 1, 1))
.having((state) => state.criterieTri, 'criterieTri', TriDemandes.dateCreation)
.having((state) => state.triCroissant, 'triCroissant', false),
],
);
});
group('SelectionnerDemandeAideEvent', () {
final tDemandes = [
_createTestDemandeAide('1', 'Demande 1'),
_createTestDemandeAide('2', 'Demande 2'),
];
blocTest<DemandesAideBloc, DemandesAideState>(
'sélectionne une demande',
build: () => bloc,
seed: () => DemandesAideLoaded(
demandes: tDemandes,
demandesFiltrees: tDemandes,
lastUpdated: DateTime.now(),
),
act: (bloc) => bloc.add(const SelectionnerDemandeAideEvent(
demandeId: '1',
selectionne: true,
)),
expect: () => [
isA<DemandesAideLoaded>()
.having((state) => state.demandesSelectionnees['1'], 'demande sélectionnée', true)
.having((state) => state.nombreDemandesSelectionnees, 'nombre sélectionnées', 1),
],
);
blocTest<DemandesAideBloc, DemandesAideState>(
'désélectionne une demande',
build: () => bloc,
seed: () => DemandesAideLoaded(
demandes: tDemandes,
demandesFiltrees: tDemandes,
demandesSelectionnees: const {'1': true},
lastUpdated: DateTime.now(),
),
act: (bloc) => bloc.add(const SelectionnerDemandeAideEvent(
demandeId: '1',
selectionne: false,
)),
expect: () => [
isA<DemandesAideLoaded>()
.having((state) => state.demandesSelectionnees.containsKey('1'), 'demande désélectionnée', false)
.having((state) => state.nombreDemandesSelectionnees, 'nombre sélectionnées', 0),
],
);
});
group('SelectionnerToutesDemandesAideEvent', () {
final tDemandes = [
_createTestDemandeAide('1', 'Demande 1'),
_createTestDemandeAide('2', 'Demande 2'),
];
blocTest<DemandesAideBloc, DemandesAideState>(
'sélectionne toutes les demandes',
build: () => bloc,
seed: () => DemandesAideLoaded(
demandes: tDemandes,
demandesFiltrees: tDemandes,
lastUpdated: DateTime.now(),
),
act: (bloc) => bloc.add(const SelectionnerToutesDemandesAideEvent(selectionne: true)),
expect: () => [
isA<DemandesAideLoaded>()
.having((state) => state.demandesSelectionnees.length, 'nombre sélectionnées', 2)
.having((state) => state.toutesDemandesSelectionnees, 'toutes sélectionnées', true),
],
);
blocTest<DemandesAideBloc, DemandesAideState>(
'désélectionne toutes les demandes',
build: () => bloc,
seed: () => DemandesAideLoaded(
demandes: tDemandes,
demandesFiltrees: tDemandes,
demandesSelectionnees: const {'1': true, '2': true},
lastUpdated: DateTime.now(),
),
act: (bloc) => bloc.add(const SelectionnerToutesDemandesAideEvent(selectionne: false)),
expect: () => [
isA<DemandesAideLoaded>()
.having((state) => state.demandesSelectionnees.isEmpty, 'aucune sélectionnée', true)
.having((state) => state.toutesDemandesSelectionnees, 'toutes désélectionnées', false),
],
);
});
group('ValiderDemandeAideEvent', () {
final tDemande = _createTestDemandeAide('1', 'Demande à valider');
blocTest<DemandesAideBloc, DemandesAideState>(
'émet DemandesAideValidation avec isValid=true quand la validation réussit',
build: () {
when(mockValiderDemandeAideUseCase(any))
.thenAnswer((_) async => const Right(true));
return bloc;
},
act: (bloc) => bloc.add(ValiderDemandeAideEvent(demande: tDemande)),
expect: () => [
isA<DemandesAideValidation>()
.having((state) => state.isValid, 'isValid', true)
.having((state) => state.erreurs.isEmpty, 'erreurs vides', true)
.having((state) => state.demande, 'demande', tDemande),
],
);
blocTest<DemandesAideBloc, DemandesAideState>(
'émet DemandesAideValidation avec erreurs quand la validation échoue',
build: () {
when(mockValiderDemandeAideUseCase(any))
.thenAnswer((_) async => const Left(ValidationFailure('Titre requis')));
return bloc;
},
act: (bloc) => bloc.add(ValiderDemandeAideEvent(demande: tDemande)),
expect: () => [
isA<DemandesAideValidation>()
.having((state) => state.isValid, 'isValid', false)
.having((state) => state.erreurs['general'], 'erreur générale', 'Titre requis')
.having((state) => state.demande, 'demande', tDemande),
],
);
});
});
}
/// Fonction utilitaire pour créer une demande d'aide de test
DemandeAide _createTestDemandeAide(
String id,
String titre, {
bool estUrgente = false,
DateTime? dateCreation,
}) {
return DemandeAide(
id: id,
numeroReference: 'REF-$id',
titre: titre,
description: 'Description de la $titre',
typeAide: TypeAide.aideFinanciereUrgente,
statut: StatutAide.brouillon,
priorite: PrioriteAide.normale,
estUrgente: estUrgente,
dateCreation: dateCreation ?? DateTime.now(),
dateModification: dateCreation ?? DateTime.now(),
organisationId: 'org-1',
demandeurId: 'user-1',
nomDemandeur: 'John Doe',
emailDemandeur: 'john@example.com',
telephoneDemandeur: '+225123456789',
beneficiaires: const [],
evaluations: const [],
commentairesInternes: const [],
historiqueStatuts: const [],
piecesJustificatives: const [],
tags: const [],
metadonnees: const {},
);
}