import 'dart:convert'; import 'package:afterwork/core/errors/exceptions.dart'; import 'package:afterwork/data/datasources/event_remote_data_source.dart'; import 'package:afterwork/data/models/event_model.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; import 'package:mocktail/mocktail.dart'; // Mock classes class MockHttpClient extends Mock implements http.Client {} void main() { late EventRemoteDataSource dataSource; late MockHttpClient mockHttpClient; setUpAll(() { // Register fallback values for mocktail registerFallbackValue(Uri.parse('http://example.com')); registerFallbackValue({}); }); setUp(() { mockHttpClient = MockHttpClient(); dataSource = EventRemoteDataSource(mockHttpClient); }); group('EventRemoteDataSource', () { final tEventJson = { 'id': '1', 'title': 'Test Event', 'description': 'Test Description', 'startDate': '2026-01-01T00:00:00Z', 'location': 'Test Location', 'category': 'Test Category', 'link': 'https://test.com', 'imageUrl': 'https://test.com/image.jpg', 'creatorEmail': 'creator@test.com', 'creatorFirstName': 'John', 'creatorLastName': 'Doe', 'profileImageUrl': 'https://test.com/profile.jpg', 'participants': ['user1', 'user2'], 'status': 'ouvert', 'reactionsCount': 5, 'commentsCount': 3, 'sharesCount': 2, }; final tEventModel = EventModel.fromJson(tEventJson); group('getAllEvents', () { test('should return list of events when API call is successful', () async { // Arrange when(() => mockHttpClient.get(any())).thenAnswer( (_) async => http.Response( jsonEncode([tEventJson]), 200, ), ); // Act final result = await dataSource.getAllEvents(); // Assert expect(result, isA>()); expect(result.length, 1); expect(result.first.id, '1'); verify(() => mockHttpClient.get(any())).called(1); }); test('should throw ServerException when API call fails', () async { // Arrange when(() => mockHttpClient.get(any())).thenAnswer( (_) async => http.Response('Error', 500), ); // Act & Assert expect( () => dataSource.getAllEvents(), throwsA(isA()), ); }); }); group('getEventsCreatedByUserAndFriends', () { const tUserId = 'user123'; test('should return list of events when API call is successful', () async { // Arrange when(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .thenAnswer( (_) async => http.Response( jsonEncode([tEventJson]), 200, ), ); // Act final result = await dataSource.getEventsCreatedByUserAndFriends(tUserId); // Assert expect(result, isA>()); expect(result.length, 1); expect(result.first.id, '1'); verify(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .called(1); }); test('should throw ServerException when API call fails', () async { // Arrange when(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .thenAnswer((_) async => http.Response('Error', 500)); // Act & Assert expect( () => dataSource.getEventsCreatedByUserAndFriends(tUserId), throwsA(isA()), ); }); test('should send correct request body', () async { // Arrange when(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .thenAnswer( (_) async => http.Response(jsonEncode([]), 200), ); // Act await dataSource.getEventsCreatedByUserAndFriends(tUserId); // Assert final captured = verify(() => mockHttpClient.post( any(), headers: any(named: 'headers'), body: captureAny(named: 'body'), )).captured; final body = jsonDecode(captured.first as String) as Map; expect(body['userId'], tUserId); }); }); group('createEvent', () { test('should return created event when API call is successful', () async { // Arrange when(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .thenAnswer( (_) async => http.Response( jsonEncode(tEventJson), 201, ), ); // Act final result = await dataSource.createEvent(tEventModel); // Assert expect(result, isA()); expect(result.id, '1'); verify(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .called(1); }); test('should throw ServerException when API call fails', () async { // Arrange when(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .thenAnswer((_) async => http.Response('Error', 400)); // Act & Assert expect( () => dataSource.createEvent(tEventModel), throwsA(isA()), ); }); }); group('getEventById', () { const tEventId = '1'; test('should return event when API call is successful', () async { // Arrange when(() => mockHttpClient.get(any())).thenAnswer( (_) async => http.Response( jsonEncode(tEventJson), 200, ), ); // Act final result = await dataSource.getEventById(tEventId); // Assert expect(result, isA()); expect(result.id, tEventId); verify(() => mockHttpClient.get(any())).called(1); }); test('should throw ServerException when API call fails', () async { // Arrange when(() => mockHttpClient.get(any())).thenAnswer( (_) async => http.Response('Error', 404), ); // Act & Assert expect( () => dataSource.getEventById(tEventId), throwsA(isA()), ); }); }); group('updateEvent', () { const tEventId = '1'; test('should return updated event when API call is successful', () async { // Arrange when(() => mockHttpClient.put(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .thenAnswer( (_) async => http.Response( jsonEncode(tEventJson), 200, ), ); // Act final result = await dataSource.updateEvent(tEventId, tEventModel); // Assert expect(result, isA()); expect(result.id, tEventId); verify(() => mockHttpClient.put(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .called(1); }); test('should throw ServerException when API call fails', () async { // Arrange when(() => mockHttpClient.put(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .thenAnswer((_) async => http.Response('Error', 400)); // Act & Assert expect( () => dataSource.updateEvent(tEventId, tEventModel), throwsA(isA()), ); }); }); group('deleteEvent', () { const tEventId = '1'; test('should delete event successfully when API call is successful', () async { // Arrange when(() => mockHttpClient.delete(any())).thenAnswer( (_) async => http.Response('', 204), ); // Act await dataSource.deleteEvent(tEventId); // Assert verify(() => mockHttpClient.delete(any())).called(1); }); test('should throw ServerException when API call fails', () async { // Arrange when(() => mockHttpClient.delete(any())).thenAnswer( (_) async => http.Response('Error', 500), ); // Act & Assert expect( () => dataSource.deleteEvent(tEventId), throwsA(isA()), ); }); }); group('participateInEvent', () { const tEventId = '1'; const tUserId = 'user123'; test('should return event when participation is successful', () async { // Arrange when(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .thenAnswer( (_) async => http.Response( jsonEncode(tEventJson), 200, ), ); // Act final result = await dataSource.participateInEvent(tEventId, tUserId); // Assert expect(result, isA()); verify(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .called(1); }); test('should throw ServerException when API call fails', () async { // Arrange when(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .thenAnswer((_) async => http.Response('Error', 400)); // Act & Assert expect( () => dataSource.participateInEvent(tEventId, tUserId), throwsA(isA()), ); }); }); group('reactToEvent', () { const tEventId = '1'; const tUserId = 'user123'; test('should react to event successfully when API call is successful', () async { // Arrange when(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .thenAnswer((_) async => http.Response('Success', 200)); // Act await dataSource.reactToEvent(tEventId, tUserId); // Assert verify(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .called(1); }); test('should throw ServerException when API call fails', () async { // Arrange when(() => mockHttpClient.post(any(), headers: any(named: 'headers'), body: any(named: 'body'))) .thenAnswer((_) async => http.Response('Error', 400)); // Act & Assert expect( () => dataSource.reactToEvent(tEventId, tUserId), throwsA(isA()), ); }); }); group('closeEvent', () { const tEventId = '1'; test('should close event successfully when API call is successful', () async { // Arrange when(() => mockHttpClient.patch(any(), headers: any(named: 'headers'))) .thenAnswer((_) async => http.Response('Success', 200)); // Act await dataSource.closeEvent(tEventId); // Assert verify(() => mockHttpClient.patch(any(), headers: any(named: 'headers'))).called(1); }); test('should throw ServerExceptionWithMessage when status code is 400', () async { // Arrange when(() => mockHttpClient.patch(any(), headers: any(named: 'headers'))) .thenAnswer( (_) async => http.Response( jsonEncode({'message': 'Event already closed'}), 400, ), ); // Act & Assert expect( () => dataSource.closeEvent(tEventId), throwsA(isA()), ); }); test('should throw ServerExceptionWithMessage when status code is not 200 or 400', () async { // Arrange when(() => mockHttpClient.patch(any(), headers: any(named: 'headers'))) .thenAnswer((_) async => http.Response('Error', 500)); // Act & Assert expect( () => dataSource.closeEvent(tEventId), throwsA(isA()), ); }); }); group('reopenEvent', () { const tEventId = '1'; test('should reopen event successfully when API call is successful', () async { // Arrange when(() => mockHttpClient.patch(any(), headers: any(named: 'headers'))) .thenAnswer((_) async => http.Response('Success', 200)); // Act await dataSource.reopenEvent(tEventId); // Assert verify(() => mockHttpClient.patch(any(), headers: any(named: 'headers'))).called(1); }); test('should throw ServerExceptionWithMessage when status code is 400', () async { // Arrange when(() => mockHttpClient.patch(any(), headers: any(named: 'headers'))) .thenAnswer( (_) async => http.Response( jsonEncode({'message': 'Event already open'}), 400, ), ); // Act & Assert expect( () => dataSource.reopenEvent(tEventId), throwsA(isA()), ); }); test('should throw ServerExceptionWithMessage when status code is 404', () async { // Arrange when(() => mockHttpClient.patch(any(), headers: any(named: 'headers'))) .thenAnswer((_) async => http.Response('Not found', 404)); // Act & Assert expect( () => dataSource.reopenEvent(tEventId), throwsA(isA()), ); }); test('should throw ServerExceptionWithMessage when status code is not 200, 400 or 404', () async { // Arrange when(() => mockHttpClient.patch(any(), headers: any(named: 'headers'))) .thenAnswer((_) async => http.Response('Error', 500)); // Act & Assert expect( () => dataSource.reopenEvent(tEventId), throwsA(isA()), ); }); }); }); }