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 {},
);
}

View File

@@ -0,0 +1,401 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:unionflow_mobile_apps/features/solidarite/domain/entities/demande_aide.dart';
import 'package:unionflow_mobile_apps/features/solidarite/presentation/widgets/demande_aide_card.dart';
void main() {
group('DemandeAideCard', () {
late DemandeAide testDemande;
setUp(() {
testDemande = DemandeAide(
id: 'demande-123',
numeroReference: 'REF-2024-001',
titre: 'Aide médicale urgente',
description: 'Besoin d\'aide pour frais médicaux d\'urgence suite à un accident',
typeAide: TypeAide.aideFinanciereMedicale,
statut: StatutAide.enAttente,
priorite: PrioriteAide.haute,
estUrgente: true,
montantDemande: 500000.0,
dateCreation: DateTime(2024, 1, 15, 10, 30),
dateModification: DateTime(2024, 1, 15, 14, 45),
organisationId: 'org-1',
demandeurId: 'user-1',
nomDemandeur: 'Marie Kouassi',
emailDemandeur: 'marie@example.com',
telephoneDemandeur: '+225123456789',
beneficiaires: const [
BeneficiaireAide(
prenom: 'Jean',
nom: 'Kouassi',
age: 25,
),
],
evaluations: const [],
commentairesInternes: const [],
historiqueStatuts: const [],
piecesJustificatives: const [],
tags: const ['urgent', 'médical'],
metadonnees: const {},
);
});
Widget createWidgetUnderTest({
DemandeAide? demande,
VoidCallback? onTap,
VoidCallback? onLongPress,
bool isSelected = false,
bool showSelection = false,
}) {
return MaterialApp(
home: Scaffold(
body: DemandeAideCard(
demande: demande ?? testDemande,
onTap: onTap,
onLongPress: onLongPress,
isSelected: isSelected,
showSelection: showSelection,
),
),
);
}
group('affichage des informations de base', () {
testWidgets('affiche le titre de la demande', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.text('Aide médicale urgente'), findsOneWidget);
});
testWidgets('affiche la description tronquée', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.textContaining('Besoin d\'aide pour frais médicaux'), findsOneWidget);
});
testWidgets('affiche le numéro de référence', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.text('REF-2024-001'), findsOneWidget);
});
testWidgets('affiche le nom du demandeur', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.text('Marie Kouassi'), findsOneWidget);
});
testWidgets('affiche le montant demandé formaté', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.text('500 000 FCFA'), findsOneWidget);
});
testWidgets('affiche la date de création formatée', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.text('15 jan. 2024'), findsOneWidget);
});
});
group('affichage des badges et indicateurs', () {
testWidgets('affiche le badge urgent pour une demande urgente', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.text('URGENT'), findsOneWidget);
expect(find.byIcon(Icons.priority_high), findsOneWidget);
});
testWidgets('n\'affiche pas le badge urgent pour une demande normale', (WidgetTester tester) async {
// arrange
final demandeNormale = testDemande.copyWith(estUrgente: false);
// act
await tester.pumpWidget(createWidgetUnderTest(demande: demandeNormale));
// assert
expect(find.text('URGENT'), findsNothing);
expect(find.byIcon(Icons.priority_high), findsNothing);
});
testWidgets('affiche le badge de statut avec la bonne couleur', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.text('En attente'), findsOneWidget);
// Vérifier la couleur du badge (orange pour "en attente")
final badgeContainer = tester.widget<Container>(
find.ancestor(
of: find.text('En attente'),
matching: find.byType(Container),
).first,
);
expect(badgeContainer.decoration, isA<BoxDecoration>());
});
testWidgets('affiche le badge de priorité', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.text('Haute'), findsOneWidget);
});
testWidgets('affiche le badge de type d\'aide', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.text('Aide médicale'), findsOneWidget);
});
});
group('affichage des informations supplémentaires', () {
testWidgets('affiche le nombre de bénéficiaires', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.text('1 bénéficiaire'), findsOneWidget);
expect(find.byIcon(Icons.people), findsOneWidget);
});
testWidgets('affiche le pluriel pour plusieurs bénéficiaires', (WidgetTester tester) async {
// arrange
final demandeAvecPlusieurs = testDemande.copyWith(
beneficiaires: const [
BeneficiaireAide(prenom: 'Jean', nom: 'Kouassi', age: 25),
BeneficiaireAide(prenom: 'Marie', nom: 'Kouassi', age: 23),
],
);
// act
await tester.pumpWidget(createWidgetUnderTest(demande: demandeAvecPlusieurs));
// assert
expect(find.text('2 bénéficiaires'), findsOneWidget);
});
testWidgets('affiche les tags', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.text('urgent'), findsOneWidget);
expect(find.text('médical'), findsOneWidget);
});
testWidgets('affiche l\'indicateur de progression', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.byType(LinearProgressIndicator), findsOneWidget);
});
});
group('interactions utilisateur', () {
testWidgets('appelle onTap quand la carte est tapée', (WidgetTester tester) async {
// arrange
bool tapCalled = false;
void onTap() => tapCalled = true;
await tester.pumpWidget(createWidgetUnderTest(onTap: onTap));
// act
await tester.tap(find.byType(DemandeAideCard));
await tester.pumpAndSettle();
// assert
expect(tapCalled, true);
});
testWidgets('appelle onLongPress quand la carte est pressée longuement', (WidgetTester tester) async {
// arrange
bool longPressCalled = false;
void onLongPress() => longPressCalled = true;
await tester.pumpWidget(createWidgetUnderTest(onLongPress: onLongPress));
// act
await tester.longPress(find.byType(DemandeAideCard));
await tester.pumpAndSettle();
// assert
expect(longPressCalled, true);
});
testWidgets('affiche l\'état sélectionné quand isSelected=true', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest(
isSelected: true,
showSelection: true,
));
// assert
expect(find.byIcon(Icons.check_circle), findsOneWidget);
// Vérifier que la carte a une bordure différente quand sélectionnée
final card = tester.widget<Card>(find.byType(Card));
expect(card.elevation, greaterThan(1.0));
});
testWidgets('affiche l\'état non sélectionné quand isSelected=false', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest(
isSelected: false,
showSelection: true,
));
// assert
expect(find.byIcon(Icons.radio_button_unchecked), findsOneWidget);
});
testWidgets('n\'affiche pas les indicateurs de sélection quand showSelection=false', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest(
isSelected: true,
showSelection: false,
));
// assert
expect(find.byIcon(Icons.check_circle), findsNothing);
expect(find.byIcon(Icons.radio_button_unchecked), findsNothing);
});
});
group('gestion des cas limites', () {
testWidgets('gère une demande sans montant', (WidgetTester tester) async {
// arrange
final demandeSansMontant = testDemande.copyWith(montantDemande: null);
// act
await tester.pumpWidget(createWidgetUnderTest(demande: demandeSansMontant));
// assert
expect(find.text('Montant non spécifié'), findsOneWidget);
});
testWidgets('gère une demande sans bénéficiaires', (WidgetTester tester) async {
// arrange
final demandeSansBeneficiaires = testDemande.copyWith(beneficiaires: const []);
// act
await tester.pumpWidget(createWidgetUnderTest(demande: demandeSansBeneficiaires));
// assert
expect(find.text('Aucun bénéficiaire'), findsOneWidget);
});
testWidgets('gère une demande sans tags', (WidgetTester tester) async {
// arrange
final demandeSansTags = testDemande.copyWith(tags: const []);
// act
await tester.pumpWidget(createWidgetUnderTest(demande: demandeSansTags));
// assert
// Les tags ne devraient pas être affichés
expect(find.text('urgent'), findsNothing);
expect(find.text('médical'), findsNothing);
});
testWidgets('gère une description très longue', (WidgetTester tester) async {
// arrange
final descriptionLongue = 'Ceci est une description très longue qui devrait être tronquée ' * 10;
final demandeDescriptionLongue = testDemande.copyWith(description: descriptionLongue);
// act
await tester.pumpWidget(createWidgetUnderTest(demande: demandeDescriptionLongue));
// assert
// Vérifier que la description est tronquée (contient "...")
final descriptionWidget = find.byType(Text).evaluate()
.where((element) => (element.widget as Text).data?.contains('...') == true)
.isNotEmpty;
expect(descriptionWidget, true);
});
testWidgets('gère un titre très long', (WidgetTester tester) async {
// arrange
final titreLong = 'Ceci est un titre très long qui devrait être géré correctement ' * 5;
final demandeTitreLong = testDemande.copyWith(titre: titreLong);
// act
await tester.pumpWidget(createWidgetUnderTest(demande: demandeTitreLong));
// assert
// Le widget ne devrait pas déborder
expect(tester.takeException(), isNull);
});
});
group('accessibilité', () {
testWidgets('a des labels d\'accessibilité appropriés', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
expect(find.bySemanticsLabel('Demande d\'aide: Aide médicale urgente'), findsOneWidget);
});
testWidgets('supporte la navigation au clavier', (WidgetTester tester) async {
// arrange & act
await tester.pumpWidget(createWidgetUnderTest());
// assert
final inkWell = find.byType(InkWell);
expect(inkWell, findsOneWidget);
final inkWellWidget = tester.widget<InkWell>(inkWell);
expect(inkWellWidget.focusNode, isNotNull);
});
});
group('performance', () {
testWidgets('se construit rapidement avec de nombreuses demandes', (WidgetTester tester) async {
// arrange
final stopwatch = Stopwatch()..start();
// act
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: ListView.builder(
itemCount: 100,
itemBuilder: (context, index) => DemandeAideCard(
demande: testDemande.copyWith(
id: 'demande-$index',
titre: 'Demande $index',
),
),
),
),
));
stopwatch.stop();
// assert
expect(stopwatch.elapsedMilliseconds, lessThan(1000)); // Moins d'1 seconde
});
});
});
}