feat: WebSocket temps réel + Finance Workflow + corrections
- Task #6: WebSocket /ws/dashboard + Kafka events (5 topics) * Backend: KafkaEventProducer, KafkaEventConsumer * Mobile: WebSocketService (reconnection, heartbeat, typed events) * DashboardBloc: Auto-refresh depuis WebSocket events - Finance Workflow: approbations + budgets (backend + mobile) * Backend: entities, services, resources, migrations Flyway V6 * Mobile: features finance_workflow complète avec BLoC - Corrections DI: interfaces IRepository partout * IProfileRepository, IOrganizationRepository, IMembreRepository * GetIt configuré avec @injectable - Spec-Kit: constitution + templates mis à jour * .specify/memory/constitution.md enrichie * Templates agent, plan, spec, tasks, checklist - Nettoyage: fichiers temporaires supprimés Signed-off-by: lions dev Team
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
/// Tests unitaires pour CancelRegistration use case
|
||||
library cancel_registration_test;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/repositories/evenement_repository.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/usecases/cancel_registration.dart';
|
||||
|
||||
@GenerateMocks([IEvenementRepository])
|
||||
import 'cancel_registration_test.mocks.dart';
|
||||
|
||||
void main() {
|
||||
late CancelRegistration useCase;
|
||||
late MockIEvenementRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockIEvenementRepository();
|
||||
useCase = CancelRegistration(mockRepository);
|
||||
});
|
||||
|
||||
group('CancelRegistration Use Case', () {
|
||||
const tEventId = 'event123';
|
||||
|
||||
test('should cancel registration successfully', () async {
|
||||
// Arrange
|
||||
when(mockRepository.desinscrireEvenement(tEventId))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
// Act
|
||||
await useCase(tEventId);
|
||||
|
||||
// Assert
|
||||
verify(mockRepository.desinscrireEvenement(tEventId));
|
||||
verifyNoMoreInteractions(mockRepository);
|
||||
});
|
||||
|
||||
test('should throw exception when event not found', () async {
|
||||
// Arrange
|
||||
when(mockRepository.desinscrireEvenement(any))
|
||||
.thenThrow(Exception('Événement non trouvé'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase('nonexistent'), throwsA(isA<Exception>()));
|
||||
});
|
||||
|
||||
test('should throw exception when not registered', () async {
|
||||
// Arrange
|
||||
when(mockRepository.desinscrireEvenement(any))
|
||||
.thenThrow(Exception('Vous n\'êtes pas inscrit à cet événement'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase(tEventId), throwsA(isA<Exception>()));
|
||||
});
|
||||
|
||||
test('should throw exception when cancellation fails', () async {
|
||||
// Arrange
|
||||
when(mockRepository.desinscrireEvenement(any))
|
||||
.thenThrow(Exception('Erreur de désinscription'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase(tEventId), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/// Tests unitaires pour CreateEvent use case
|
||||
library create_event_test;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/repositories/evenement_repository.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/usecases/create_event.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/data/models/evenement_model.dart';
|
||||
|
||||
@GenerateMocks([IEvenementRepository])
|
||||
import 'create_event_test.mocks.dart';
|
||||
|
||||
void main() {
|
||||
late CreateEvent useCase;
|
||||
late MockIEvenementRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockIEvenementRepository();
|
||||
useCase = CreateEvent(mockRepository);
|
||||
});
|
||||
|
||||
group('CreateEvent Use Case', () {
|
||||
final tNewEvent = EvenementModel(
|
||||
titre: 'Nouvelle Réunion',
|
||||
description: 'Réunion mensuelle du comité',
|
||||
dateDebut: DateTime(2025, 1, 15, 10, 0),
|
||||
dateFin: DateTime(2025, 1, 15, 12, 0),
|
||||
lieu: 'Salle de réunion',
|
||||
type: TypeEvenement.reunion,
|
||||
statut: StatutEvenement.planifie,
|
||||
);
|
||||
|
||||
final tCreatedEvent = EvenementModel(
|
||||
id: 456,
|
||||
titre: 'Nouvelle Réunion',
|
||||
description: 'Réunion mensuelle du comité',
|
||||
dateDebut: DateTime(2025, 1, 15, 10, 0),
|
||||
dateFin: DateTime(2025, 1, 15, 12, 0),
|
||||
lieu: 'Salle de réunion',
|
||||
type: TypeEvenement.reunion,
|
||||
statut: StatutEvenement.planifie,
|
||||
);
|
||||
|
||||
test('should create event successfully', () async {
|
||||
// Arrange
|
||||
when(mockRepository.createEvenement(tNewEvent))
|
||||
.thenAnswer((_) async => tCreatedEvent);
|
||||
|
||||
// Act
|
||||
final result = await useCase(tNewEvent);
|
||||
|
||||
// Assert
|
||||
expect(result, equals(tCreatedEvent));
|
||||
expect(result.id, isNotNull);
|
||||
expect(result.id, equals(456));
|
||||
expect(result.titre, equals('Nouvelle Réunion'));
|
||||
verify(mockRepository.createEvenement(tNewEvent));
|
||||
verifyNoMoreInteractions(mockRepository);
|
||||
});
|
||||
|
||||
test('should create public event with registration', () async {
|
||||
// Arrange
|
||||
final publicEvent = EvenementModel(
|
||||
titre: 'Conférence Publique',
|
||||
dateDebut: DateTime(2025, 2, 1, 14, 0),
|
||||
dateFin: DateTime(2025, 2, 1, 17, 0),
|
||||
type: TypeEvenement.conference,
|
||||
statut: StatutEvenement.planifie,
|
||||
estPublic: true,
|
||||
inscriptionRequise: true,
|
||||
maxParticipants: 200,
|
||||
);
|
||||
final createdPublic = publicEvent.copyWith(id: 789);
|
||||
when(mockRepository.createEvenement(publicEvent))
|
||||
.thenAnswer((_) async => createdPublic);
|
||||
|
||||
// Act
|
||||
final result = await useCase(publicEvent);
|
||||
|
||||
// Assert
|
||||
expect(result.estPublic, isTrue);
|
||||
expect(result.inscriptionRequise, isTrue);
|
||||
expect(result.maxParticipants, equals(200));
|
||||
});
|
||||
|
||||
test('should create event with cost', () async {
|
||||
// Arrange
|
||||
final paidEvent = EvenementModel(
|
||||
titre: 'Séminaire Payant',
|
||||
dateDebut: DateTime(2025, 3, 1, 9, 0),
|
||||
dateFin: DateTime(2025, 3, 1, 18, 0),
|
||||
type: TypeEvenement.seminaire,
|
||||
statut: StatutEvenement.planifie,
|
||||
cout: 50000.0,
|
||||
devise: 'XOF',
|
||||
);
|
||||
when(mockRepository.createEvenement(any))
|
||||
.thenAnswer((_) async => paidEvent.copyWith(id: 999));
|
||||
|
||||
// Act
|
||||
final result = await useCase(paidEvent);
|
||||
|
||||
// Assert
|
||||
expect(result.cout, equals(50000.0));
|
||||
expect(result.devise, equals('XOF'));
|
||||
});
|
||||
|
||||
test('should throw exception when creation fails', () async {
|
||||
// Arrange
|
||||
when(mockRepository.createEvenement(any))
|
||||
.thenThrow(Exception('Validation error'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase(tNewEvent), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/// Tests unitaires pour DeleteEvent use case
|
||||
library delete_event_test;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/repositories/evenement_repository.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/usecases/delete_event.dart';
|
||||
|
||||
@GenerateMocks([IEvenementRepository])
|
||||
import 'delete_event_test.mocks.dart';
|
||||
|
||||
void main() {
|
||||
late DeleteEvent useCase;
|
||||
late MockIEvenementRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockIEvenementRepository();
|
||||
useCase = DeleteEvent(mockRepository);
|
||||
});
|
||||
|
||||
group('DeleteEvent Use Case', () {
|
||||
const tEventId = 'event123';
|
||||
|
||||
test('should delete event successfully', () async {
|
||||
// Arrange
|
||||
when(mockRepository.deleteEvenement(tEventId))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
// Act
|
||||
await useCase(tEventId);
|
||||
|
||||
// Assert
|
||||
verify(mockRepository.deleteEvenement(tEventId));
|
||||
verifyNoMoreInteractions(mockRepository);
|
||||
});
|
||||
|
||||
test('should throw exception when event not found', () async {
|
||||
// Arrange
|
||||
when(mockRepository.deleteEvenement(any))
|
||||
.thenThrow(Exception('Événement non trouvé'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase('nonexistent'), throwsA(isA<Exception>()));
|
||||
verify(mockRepository.deleteEvenement('nonexistent'));
|
||||
});
|
||||
|
||||
test('should throw exception when event has participants', () async {
|
||||
// Arrange
|
||||
when(mockRepository.deleteEvenement(any))
|
||||
.thenThrow(Exception('Impossible de supprimer un événement avec des participants'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase(tEventId), throwsA(isA<Exception>()));
|
||||
});
|
||||
|
||||
test('should throw exception when deletion fails', () async {
|
||||
// Arrange
|
||||
when(mockRepository.deleteEvenement(any))
|
||||
.thenThrow(Exception('Erreur de suppression'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase(tEventId), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/// Tests unitaires pour GetEventById use case
|
||||
library get_event_by_id_test;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/repositories/evenement_repository.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/usecases/get_event_by_id.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/data/models/evenement_model.dart';
|
||||
|
||||
@GenerateMocks([IEvenementRepository])
|
||||
import 'get_event_by_id_test.mocks.dart';
|
||||
|
||||
void main() {
|
||||
late GetEventById useCase;
|
||||
late MockIEvenementRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockIEvenementRepository();
|
||||
useCase = GetEventById(mockRepository);
|
||||
});
|
||||
|
||||
group('GetEventById Use Case', () {
|
||||
const tEventId = 'event123';
|
||||
final tEvent = EvenementModel(
|
||||
id: 123,
|
||||
titre: 'Assemblée Générale 2024',
|
||||
description: 'Assemblée générale annuelle de l\'organisation',
|
||||
dateDebut: DateTime(2024, 12, 15, 14, 0),
|
||||
dateFin: DateTime(2024, 12, 15, 18, 0),
|
||||
lieu: 'Salle des Congrès',
|
||||
adresse: '123 Rue de la République',
|
||||
ville: 'Dakar',
|
||||
type: TypeEvenement.assembleeGenerale,
|
||||
statut: StatutEvenement.confirme,
|
||||
priorite: PrioriteEvenement.haute,
|
||||
participantsActuels: 45,
|
||||
maxParticipants: 100,
|
||||
estPublic: true,
|
||||
inscriptionRequise: true,
|
||||
);
|
||||
|
||||
test('should return event by id', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getEvenementById(tEventId))
|
||||
.thenAnswer((_) async => tEvent);
|
||||
|
||||
// Act
|
||||
final result = await useCase(tEventId);
|
||||
|
||||
// Assert
|
||||
expect(result, equals(tEvent));
|
||||
expect(result?.id, equals(123));
|
||||
expect(result?.titre, equals('Assemblée Générale 2024'));
|
||||
verify(mockRepository.getEvenementById(tEventId));
|
||||
verifyNoMoreInteractions(mockRepository);
|
||||
});
|
||||
|
||||
test('should return event with all details populated', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getEvenementById(tEventId))
|
||||
.thenAnswer((_) async => tEvent);
|
||||
|
||||
// Act
|
||||
final result = await useCase(tEventId);
|
||||
|
||||
// Assert
|
||||
expect(result?.lieu, isNotNull);
|
||||
expect(result?.adresse, isNotNull);
|
||||
expect(result?.participantsActuels, equals(45));
|
||||
expect(result?.maxParticipants, equals(100));
|
||||
});
|
||||
|
||||
test('should return null when event not found', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getEvenementById(any))
|
||||
.thenAnswer((_) async => null);
|
||||
|
||||
// Act
|
||||
final result = await useCase('nonexistent');
|
||||
|
||||
// Assert
|
||||
expect(result, isNull);
|
||||
});
|
||||
|
||||
test('should throw exception when repository fails', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getEvenementById(any))
|
||||
.thenThrow(Exception('Database error'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase(tEventId), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/// Tests unitaires pour GetEventParticipants use case
|
||||
library get_event_participants_test;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/repositories/evenement_repository.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/usecases/get_event_participants.dart';
|
||||
|
||||
@GenerateMocks([IEvenementRepository])
|
||||
import 'get_event_participants_test.mocks.dart';
|
||||
|
||||
void main() {
|
||||
late GetEventParticipants useCase;
|
||||
late MockIEvenementRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockIEvenementRepository();
|
||||
useCase = GetEventParticipants(mockRepository);
|
||||
});
|
||||
|
||||
group('GetEventParticipants Use Case', () {
|
||||
const tEventId = 'event123';
|
||||
final tParticipantsList = [
|
||||
{
|
||||
'id': 'membre1',
|
||||
'nom': 'Dupont',
|
||||
'prenom': 'Jean',
|
||||
'email': 'jean.dupont@example.com',
|
||||
'dateInscription': '2024-11-01T10:00:00Z',
|
||||
'statut': 'CONFIRME',
|
||||
},
|
||||
{
|
||||
'id': 'membre2',
|
||||
'nom': 'Martin',
|
||||
'prenom': 'Marie',
|
||||
'email': 'marie.martin@example.com',
|
||||
'dateInscription': '2024-11-02T14:00:00Z',
|
||||
'statut': 'EN_ATTENTE',
|
||||
},
|
||||
{
|
||||
'id': 'membre3',
|
||||
'nom': 'Diallo',
|
||||
'prenom': 'Amadou',
|
||||
'email': 'amadou.diallo@example.com',
|
||||
'dateInscription': '2024-11-03T09:00:00Z',
|
||||
'statut': 'CONFIRME',
|
||||
},
|
||||
];
|
||||
|
||||
test('should return list of event participants', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getParticipants(tEventId))
|
||||
.thenAnswer((_) async => tParticipantsList);
|
||||
|
||||
// Act
|
||||
final result = await useCase(tEventId);
|
||||
|
||||
// Assert
|
||||
expect(result, equals(tParticipantsList));
|
||||
expect(result.length, equals(3));
|
||||
expect(result[0]['nom'], equals('Dupont'));
|
||||
expect(result[0]['statut'], equals('CONFIRME'));
|
||||
verify(mockRepository.getParticipants(tEventId));
|
||||
verifyNoMoreInteractions(mockRepository);
|
||||
});
|
||||
|
||||
test('should return participants with different statuses', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getParticipants(tEventId))
|
||||
.thenAnswer((_) async => tParticipantsList);
|
||||
|
||||
// Act
|
||||
final result = await useCase(tEventId);
|
||||
|
||||
// Assert
|
||||
expect(result.where((p) => p['statut'] == 'CONFIRME').length, equals(2));
|
||||
expect(result.where((p) => p['statut'] == 'EN_ATTENTE').length, equals(1));
|
||||
});
|
||||
|
||||
test('should return empty list when no participants', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getParticipants(tEventId))
|
||||
.thenAnswer((_) async => []);
|
||||
|
||||
// Act
|
||||
final result = await useCase(tEventId);
|
||||
|
||||
// Assert
|
||||
expect(result, isEmpty);
|
||||
});
|
||||
|
||||
test('should throw exception when event not found', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getParticipants(any))
|
||||
.thenThrow(Exception('Événement non trouvé'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase('nonexistent'), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/// Tests unitaires pour GetEvents use case
|
||||
library get_events_test;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/repositories/evenement_repository.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/usecases/get_events.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/data/models/evenement_model.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/data/repositories/evenement_repository_impl.dart';
|
||||
|
||||
@GenerateMocks([IEvenementRepository])
|
||||
import 'get_events_test.mocks.dart';
|
||||
|
||||
void main() {
|
||||
late GetEvents useCase;
|
||||
late MockIEvenementRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockIEvenementRepository();
|
||||
useCase = GetEvents(mockRepository);
|
||||
});
|
||||
|
||||
group('GetEvents Use Case', () {
|
||||
final tEventsList = [
|
||||
EvenementModel(
|
||||
id: 1,
|
||||
titre: 'Assemblée Générale 2024',
|
||||
description: 'Assemblée générale annuelle',
|
||||
dateDebut: DateTime(2024, 12, 15, 14, 0),
|
||||
dateFin: DateTime(2024, 12, 15, 18, 0),
|
||||
lieu: 'Salle des Congrès',
|
||||
type: TypeEvenement.assembleeGenerale,
|
||||
statut: StatutEvenement.confirme,
|
||||
priorite: PrioriteEvenement.haute,
|
||||
participantsActuels: 45,
|
||||
maxParticipants: 100,
|
||||
),
|
||||
EvenementModel(
|
||||
id: 2,
|
||||
titre: 'Formation Leadership',
|
||||
description: 'Formation sur le leadership',
|
||||
dateDebut: DateTime(2024, 12, 20, 9, 0),
|
||||
dateFin: DateTime(2024, 12, 20, 17, 0),
|
||||
lieu: 'Centre de Formation',
|
||||
type: TypeEvenement.formation,
|
||||
statut: StatutEvenement.planifie,
|
||||
participantsActuels: 15,
|
||||
maxParticipants: 30,
|
||||
),
|
||||
];
|
||||
|
||||
final tSearchResult = EvenementSearchResult(
|
||||
evenements: tEventsList,
|
||||
total: 2,
|
||||
page: 0,
|
||||
size: 20,
|
||||
totalPages: 1,
|
||||
);
|
||||
|
||||
test('should return paginated list of events', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getEvenements(
|
||||
page: anyNamed('page'),
|
||||
size: anyNamed('size'),
|
||||
recherche: anyNamed('recherche'),
|
||||
)).thenAnswer((_) async => tSearchResult);
|
||||
|
||||
// Act
|
||||
final result = await useCase(page: 0, size: 20);
|
||||
|
||||
// Assert
|
||||
expect(result, equals(tSearchResult));
|
||||
expect(result.evenements.length, equals(2));
|
||||
expect(result.total, equals(2));
|
||||
verify(mockRepository.getEvenements(page: 0, size: 20));
|
||||
verifyNoMoreInteractions(mockRepository);
|
||||
});
|
||||
|
||||
test('should filter events by search query', () async {
|
||||
// Arrange
|
||||
final filteredResult = EvenementSearchResult(
|
||||
evenements: [tEventsList[0]],
|
||||
total: 1,
|
||||
page: 0,
|
||||
size: 20,
|
||||
totalPages: 1,
|
||||
);
|
||||
when(mockRepository.getEvenements(
|
||||
page: 0,
|
||||
size: 20,
|
||||
recherche: 'Assemblée',
|
||||
)).thenAnswer((_) async => filteredResult);
|
||||
|
||||
// Act
|
||||
final result = await useCase(page: 0, size: 20, recherche: 'Assemblée');
|
||||
|
||||
// Assert
|
||||
expect(result.evenements.length, equals(1));
|
||||
expect(result.evenements.first.titre, contains('Assemblée'));
|
||||
});
|
||||
|
||||
test('should return empty result when no events exist', () async {
|
||||
// Arrange
|
||||
final emptyResult = EvenementSearchResult(
|
||||
evenements: [],
|
||||
total: 0,
|
||||
page: 0,
|
||||
size: 20,
|
||||
totalPages: 0,
|
||||
);
|
||||
when(mockRepository.getEvenements(
|
||||
page: anyNamed('page'),
|
||||
size: anyNamed('size'),
|
||||
recherche: anyNamed('recherche'),
|
||||
)).thenAnswer((_) async => emptyResult);
|
||||
|
||||
// Act
|
||||
final result = await useCase(page: 0, size: 20);
|
||||
|
||||
// Assert
|
||||
expect(result.evenements, isEmpty);
|
||||
expect(result.total, equals(0));
|
||||
});
|
||||
|
||||
test('should throw exception when repository fails', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getEvenements(
|
||||
page: anyNamed('page'),
|
||||
size: anyNamed('size'),
|
||||
recherche: anyNamed('recherche'),
|
||||
)).thenThrow(Exception('Network error'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase(page: 0, size: 20), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/// Tests unitaires pour GetMyRegistrations use case
|
||||
library get_my_registrations_test;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/repositories/evenement_repository.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/usecases/get_my_registrations.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/data/models/evenement_model.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/data/repositories/evenement_repository_impl.dart';
|
||||
|
||||
@GenerateMocks([IEvenementRepository])
|
||||
import 'get_my_registrations_test.mocks.dart';
|
||||
|
||||
void main() {
|
||||
late GetMyRegistrations useCase;
|
||||
late MockIEvenementRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockIEvenementRepository();
|
||||
useCase = GetMyRegistrations(mockRepository);
|
||||
});
|
||||
|
||||
group('GetMyRegistrations Use Case', () {
|
||||
final tRegisteredEvents = [
|
||||
EvenementModel(
|
||||
id: 1,
|
||||
titre: 'Formation Leadership',
|
||||
dateDebut: DateTime(2024, 12, 20, 9, 0),
|
||||
dateFin: DateTime(2024, 12, 20, 17, 0),
|
||||
type: TypeEvenement.formation,
|
||||
statut: StatutEvenement.confirme,
|
||||
inscriptionRequise: true,
|
||||
participantsActuels: 15,
|
||||
),
|
||||
EvenementModel(
|
||||
id: 2,
|
||||
titre: 'Séminaire Annuel',
|
||||
dateDebut: DateTime(2025, 1, 10, 14, 0),
|
||||
dateFin: DateTime(2025, 1, 10, 18, 0),
|
||||
type: TypeEvenement.seminaire,
|
||||
statut: StatutEvenement.planifie,
|
||||
inscriptionRequise: true,
|
||||
participantsActuels: 30,
|
||||
),
|
||||
];
|
||||
|
||||
final tSearchResult = EvenementSearchResult(
|
||||
evenements: tRegisteredEvents,
|
||||
total: 2,
|
||||
page: 0,
|
||||
size: 20,
|
||||
totalPages: 1,
|
||||
);
|
||||
|
||||
test('should return list of registered events', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getEvenementsAVenir(page: anyNamed('page'), size: anyNamed('size')))
|
||||
.thenAnswer((_) async => tSearchResult);
|
||||
|
||||
// Act
|
||||
final result = await useCase(page: 0, size: 20);
|
||||
|
||||
// Assert
|
||||
expect(result, equals(tSearchResult));
|
||||
expect(result.evenements.length, equals(2));
|
||||
expect(result.total, equals(2));
|
||||
verify(mockRepository.getEvenementsAVenir(page: 0, size: 20));
|
||||
verifyNoMoreInteractions(mockRepository);
|
||||
});
|
||||
|
||||
test('should return events with custom page size', () async {
|
||||
// Arrange
|
||||
final smallResult = EvenementSearchResult(
|
||||
evenements: [tRegisteredEvents[0]],
|
||||
total: 2,
|
||||
page: 0,
|
||||
size: 1,
|
||||
totalPages: 2,
|
||||
);
|
||||
when(mockRepository.getEvenementsAVenir(page: 0, size: 1))
|
||||
.thenAnswer((_) async => smallResult);
|
||||
|
||||
// Act
|
||||
final result = await useCase(page: 0, size: 1);
|
||||
|
||||
// Assert
|
||||
expect(result.evenements.length, equals(1));
|
||||
expect(result.size, equals(1));
|
||||
});
|
||||
|
||||
test('should return empty result when no registrations', () async {
|
||||
// Arrange
|
||||
final emptyResult = EvenementSearchResult(
|
||||
evenements: [],
|
||||
total: 0,
|
||||
page: 0,
|
||||
size: 20,
|
||||
totalPages: 0,
|
||||
);
|
||||
when(mockRepository.getEvenementsAVenir(page: anyNamed('page'), size: anyNamed('size')))
|
||||
.thenAnswer((_) async => emptyResult);
|
||||
|
||||
// Act
|
||||
final result = await useCase(page: 0, size: 20);
|
||||
|
||||
// Assert
|
||||
expect(result.evenements, isEmpty);
|
||||
expect(result.total, equals(0));
|
||||
});
|
||||
|
||||
test('should throw exception when repository fails', () async {
|
||||
// Arrange
|
||||
when(mockRepository.getEvenementsAVenir(page: anyNamed('page'), size: anyNamed('size')))
|
||||
.thenThrow(Exception('Network error'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase(page: 0, size: 20), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/// Tests unitaires pour RegisterForEvent use case
|
||||
library register_for_event_test;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/repositories/evenement_repository.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/usecases/register_for_event.dart';
|
||||
|
||||
@GenerateMocks([IEvenementRepository])
|
||||
import 'register_for_event_test.mocks.dart';
|
||||
|
||||
void main() {
|
||||
late RegisterForEvent useCase;
|
||||
late MockIEvenementRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockIEvenementRepository();
|
||||
useCase = RegisterForEvent(mockRepository);
|
||||
});
|
||||
|
||||
group('RegisterForEvent Use Case', () {
|
||||
const tEventId = 'event123';
|
||||
|
||||
test('should register for event successfully', () async {
|
||||
// Arrange
|
||||
when(mockRepository.inscrireEvenement(tEventId))
|
||||
.thenAnswer((_) async => Future.value());
|
||||
|
||||
// Act
|
||||
await useCase(tEventId);
|
||||
|
||||
// Assert
|
||||
verify(mockRepository.inscrireEvenement(tEventId));
|
||||
verifyNoMoreInteractions(mockRepository);
|
||||
});
|
||||
|
||||
test('should throw exception when event not found', () async {
|
||||
// Arrange
|
||||
when(mockRepository.inscrireEvenement(any))
|
||||
.thenThrow(Exception('Événement non trouvé'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase('nonexistent'), throwsA(isA<Exception>()));
|
||||
});
|
||||
|
||||
test('should throw exception when already registered', () async {
|
||||
// Arrange
|
||||
when(mockRepository.inscrireEvenement(any))
|
||||
.thenThrow(Exception('Vous êtes déjà inscrit à cet événement'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase(tEventId), throwsA(isA<Exception>()));
|
||||
});
|
||||
|
||||
test('should throw exception when event is full', () async {
|
||||
// Arrange
|
||||
when(mockRepository.inscrireEvenement(any))
|
||||
.thenThrow(Exception('Événement complet'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase(tEventId), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/// Tests unitaires pour SubmitEventFeedback use case
|
||||
library submit_event_feedback_test;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/repositories/evenement_repository.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/usecases/submit_event_feedback.dart';
|
||||
|
||||
@GenerateMocks([IEvenementRepository])
|
||||
import 'submit_event_feedback_test.mocks.dart';
|
||||
|
||||
void main() {
|
||||
late SubmitEventFeedback useCase;
|
||||
late MockIEvenementRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockIEvenementRepository();
|
||||
useCase = SubmitEventFeedback(mockRepository);
|
||||
});
|
||||
|
||||
group('SubmitEventFeedback Use Case', () {
|
||||
const tEventId = 'event123';
|
||||
const tNote = 5;
|
||||
const tCommentaire = 'Excellent événement, très enrichissant!';
|
||||
|
||||
test('should throw UnimplementedError as endpoint not available', () async {
|
||||
// Act & Assert
|
||||
expect(
|
||||
() => useCase(evenementId: tEventId, note: tNote),
|
||||
throwsA(isA<UnimplementedError>()),
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw UnimplementedError with feedback message', () async {
|
||||
// Act & Assert
|
||||
expect(
|
||||
() => useCase(
|
||||
evenementId: tEventId,
|
||||
note: tNote,
|
||||
commentaire: tCommentaire,
|
||||
),
|
||||
throwsA(isA<UnimplementedError>()),
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw UnimplementedError for minimum rating', () async {
|
||||
// Act & Assert
|
||||
expect(
|
||||
() => useCase(evenementId: tEventId, note: 1),
|
||||
throwsA(isA<UnimplementedError>()),
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw UnimplementedError for maximum rating', () async {
|
||||
// Act & Assert
|
||||
expect(
|
||||
() => useCase(
|
||||
evenementId: tEventId,
|
||||
note: 5,
|
||||
commentaire: 'Parfait!',
|
||||
),
|
||||
throwsA(isA<UnimplementedError>()),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/// Tests unitaires pour UpdateEvent use case
|
||||
library update_event_test;
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/repositories/evenement_repository.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/domain/usecases/update_event.dart';
|
||||
import 'package:unionflow_mobile_apps/features/events/data/models/evenement_model.dart';
|
||||
|
||||
@GenerateMocks([IEvenementRepository])
|
||||
import 'update_event_test.mocks.dart';
|
||||
|
||||
void main() {
|
||||
late UpdateEvent useCase;
|
||||
late MockIEvenementRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockIEvenementRepository();
|
||||
useCase = UpdateEvent(mockRepository);
|
||||
});
|
||||
|
||||
group('UpdateEvent Use Case', () {
|
||||
const tEventId = 'event123';
|
||||
final tUpdatedEvent = EvenementModel(
|
||||
id: 123,
|
||||
titre: 'Assemblée Générale 2024 - Modifiée',
|
||||
description: 'Assemblée générale annuelle (mise à jour)',
|
||||
dateDebut: DateTime(2024, 12, 16, 14, 0),
|
||||
dateFin: DateTime(2024, 12, 16, 18, 0),
|
||||
lieu: 'Nouveau lieu',
|
||||
type: TypeEvenement.assembleeGenerale,
|
||||
statut: StatutEvenement.confirme,
|
||||
);
|
||||
|
||||
test('should update event successfully', () async {
|
||||
// Arrange
|
||||
when(mockRepository.updateEvenement(tEventId, tUpdatedEvent))
|
||||
.thenAnswer((_) async => tUpdatedEvent);
|
||||
|
||||
// Act
|
||||
final result = await useCase(tEventId, tUpdatedEvent);
|
||||
|
||||
// Assert
|
||||
expect(result, equals(tUpdatedEvent));
|
||||
expect(result.titre, contains('Modifiée'));
|
||||
expect(result.lieu, equals('Nouveau lieu'));
|
||||
verify(mockRepository.updateEvenement(tEventId, tUpdatedEvent));
|
||||
verifyNoMoreInteractions(mockRepository);
|
||||
});
|
||||
|
||||
test('should update event status', () async {
|
||||
// Arrange
|
||||
final statusUpdate = EvenementModel(
|
||||
id: 123,
|
||||
titre: 'Événement',
|
||||
dateDebut: DateTime(2024, 12, 15, 14, 0),
|
||||
dateFin: DateTime(2024, 12, 15, 18, 0),
|
||||
type: TypeEvenement.reunion,
|
||||
statut: StatutEvenement.annule,
|
||||
);
|
||||
when(mockRepository.updateEvenement(tEventId, statusUpdate))
|
||||
.thenAnswer((_) async => statusUpdate);
|
||||
|
||||
// Act
|
||||
final result = await useCase(tEventId, statusUpdate);
|
||||
|
||||
// Assert
|
||||
expect(result.statut, equals(StatutEvenement.annule));
|
||||
});
|
||||
|
||||
test('should update event capacity', () async {
|
||||
// Arrange
|
||||
final capacityUpdate = EvenementModel(
|
||||
id: 123,
|
||||
titre: 'Événement',
|
||||
dateDebut: DateTime(2024, 12, 15, 14, 0),
|
||||
dateFin: DateTime(2024, 12, 15, 18, 0),
|
||||
type: TypeEvenement.formation,
|
||||
statut: StatutEvenement.planifie,
|
||||
maxParticipants: 50,
|
||||
participantsActuels: 25,
|
||||
);
|
||||
when(mockRepository.updateEvenement(tEventId, capacityUpdate))
|
||||
.thenAnswer((_) async => capacityUpdate);
|
||||
|
||||
// Act
|
||||
final result = await useCase(tEventId, capacityUpdate);
|
||||
|
||||
// Assert
|
||||
expect(result.maxParticipants, equals(50));
|
||||
expect(result.participantsActuels, equals(25));
|
||||
});
|
||||
|
||||
test('should throw exception when update fails', () async {
|
||||
// Arrange
|
||||
when(mockRepository.updateEvenement(any, any))
|
||||
.thenThrow(Exception('Update failed'));
|
||||
|
||||
// Act & Assert
|
||||
expect(() => useCase(tEventId, tUpdatedEvent), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user