From 070a3e39e74456c32429e22cc2a2919d9b1ee2d7 Mon Sep 17 00:00:00 2001 From: misha Date: Thu, 11 Dec 2025 15:53:35 +0300 Subject: [PATCH] feat(tests): added services tests and fixtures --- .../models/chat_room_pagination_model.dart | 12 +- .../auth/services/auth_service_test.dart | 70 +++++ .../services/reset_password_service_test.dart | 57 ++++ .../services/blog_post_service_test.dart | 53 ++++ .../services/calendar_service_test.dart | 34 +++ .../service/cancel_plan_service_test.dart | 39 +++ .../chat/models/chat_message_model_test.dart | 25 +- .../chat/models/chat_messages_model_test.dart | 28 +- .../chat/models/chat_room_model_test.dart | 47 +--- .../chat_room_pagination_model_test.dart | 126 ++------- .../repositories/chat_repository_test.dart | 172 ++---------- .../chat/services/chat_service_test.dart | 247 ++++-------------- .../services/complaining_service_test.dart | 58 ++++ .../services/consultant_service_test.dart | 75 ++++++ .../consultant_rating_service_test.dart | 55 ++++ .../consultations_repository_test.dart | 10 +- .../services/consultation_service_test.dart | 94 +++++++ .../services/create_diet_service_test.dart | 53 ++++ .../services/create_plan_service_test.dart | 30 +++ .../services/recipe_service_test.dart | 88 +++++++ .../repositories/diary_repository_test.dart | 94 +------ .../repositories/diet_repository_test.dart | 117 +-------- .../repositories/feed_repository_test.dart | 92 +------ .../services/glossary_service_test.dart | 35 +++ .../my_diets_repository_test.dart | 73 ++---- .../services/cards_service_test.dart | 78 ++++++ .../my_plans_repository_test.dart | 30 +-- .../service/notifications_service_test.dart | 185 +++---------- ...personal_diet_suggestion_service_test.dart | 74 ++++++ .../repositories/plans_repository_test.dart | 39 +-- .../my_recipes_repository_test.dart | 86 ++---- .../services/registration_service_test.dart | 60 +++++ test/fixtures/calendar/calendar_response.json | 13 + test/fixtures/chat/chat_message_response.json | 11 + .../chat_message_with_media_response.json | 16 ++ .../fixtures/chat/chat_messages_response.json | 28 ++ .../chat/chat_room_pagination_response.json | 64 +++++ test/fixtures/chat/chat_room_response.json | 23 ++ .../chat/chat_room_settings_response.json | 5 + .../chat/chat_room_with_plan_response.json | 69 +++++ test/fixtures/chat/chat_user_response.json | 7 + test/fixtures/chat/chosen_plan_response.json | 47 ++++ test/fixtures/chat/payment_response.json | 4 + .../fixtures/chat/plan_complain_response.json | 4 + .../chat/websocket_info_response.json | 8 + .../consultation_pagination_response.json | 33 +++ .../consultations/statistic_response.json | 7 + test/fixtures/diary/diary_day_response.json | 38 +++ .../diary/diary_day_wrapper_response.json | 40 +++ .../diary/glossary_pagination_response.json | 18 ++ test/fixtures/diary/nutrition_response.json | 15 ++ test/fixtures/diets/diet_likes_response.json | 5 + test/fixtures/diets/diet_response.json | 31 +++ test/fixtures/feed/comment_response.json | 32 +++ .../feed/consultant_pagination_response.json | 32 +++ .../feed/diets_pagination_response.json | 53 ++++ .../feed/feed_blog_post_response.json | 23 ++ .../feed_blog_posts_settings_response.json | 39 +++ .../feed/plan_pagination_response.json | 63 +++++ .../feed/recipes_pagination_response.json | 53 ++++ .../notifications/notifications_response.json | 16 ++ test/fixtures/plans/plan_response.json | 35 +++ .../my_recipe_pagination_response.json | 25 ++ test/fixtures/recipes/my_recipe_response.json | 21 ++ .../registration/location_response.json | 8 + 65 files changed, 2092 insertions(+), 1130 deletions(-) create mode 100644 test/features/auth/services/auth_service_test.dart create mode 100644 test/features/auth/services/reset_password_service_test.dart create mode 100644 test/features/blog_post_create/services/blog_post_service_test.dart create mode 100644 test/features/calendar/services/calendar_service_test.dart create mode 100644 test/features/cancel_plan_bottom_sheet/service/cancel_plan_service_test.dart create mode 100644 test/features/complaining/services/complaining_service_test.dart create mode 100644 test/features/consultant/become_consultant/services/consultant_service_test.dart create mode 100644 test/features/consultant_rating/services/consultant_rating_service_test.dart create mode 100644 test/features/consultations/services/consultation_service_test.dart create mode 100644 test/features/create_diet/services/create_diet_service_test.dart create mode 100644 test/features/create_plan/services/create_plan_service_test.dart create mode 100644 test/features/create_recipe/services/recipe_service_test.dart create mode 100644 test/features/glossary/services/glossary_service_test.dart create mode 100644 test/features/my_finance/services/cards_service_test.dart create mode 100644 test/features/personal_diet_suggestion/services/personal_diet_suggestion_service_test.dart create mode 100644 test/features/registration/services/registration_service_test.dart create mode 100644 test/fixtures/calendar/calendar_response.json create mode 100644 test/fixtures/chat/chat_message_response.json create mode 100644 test/fixtures/chat/chat_message_with_media_response.json create mode 100644 test/fixtures/chat/chat_messages_response.json create mode 100644 test/fixtures/chat/chat_room_pagination_response.json create mode 100644 test/fixtures/chat/chat_room_response.json create mode 100644 test/fixtures/chat/chat_room_settings_response.json create mode 100644 test/fixtures/chat/chat_room_with_plan_response.json create mode 100644 test/fixtures/chat/chat_user_response.json create mode 100644 test/fixtures/chat/chosen_plan_response.json create mode 100644 test/fixtures/chat/payment_response.json create mode 100644 test/fixtures/chat/plan_complain_response.json create mode 100644 test/fixtures/chat/websocket_info_response.json create mode 100644 test/fixtures/consultations/consultation_pagination_response.json create mode 100644 test/fixtures/consultations/statistic_response.json create mode 100644 test/fixtures/diary/diary_day_response.json create mode 100644 test/fixtures/diary/diary_day_wrapper_response.json create mode 100644 test/fixtures/diary/glossary_pagination_response.json create mode 100644 test/fixtures/diary/nutrition_response.json create mode 100644 test/fixtures/diets/diet_likes_response.json create mode 100644 test/fixtures/diets/diet_response.json create mode 100644 test/fixtures/feed/comment_response.json create mode 100644 test/fixtures/feed/consultant_pagination_response.json create mode 100644 test/fixtures/feed/diets_pagination_response.json create mode 100644 test/fixtures/feed/feed_blog_post_response.json create mode 100644 test/fixtures/feed/feed_blog_posts_settings_response.json create mode 100644 test/fixtures/feed/plan_pagination_response.json create mode 100644 test/fixtures/feed/recipes_pagination_response.json create mode 100644 test/fixtures/notifications/notifications_response.json create mode 100644 test/fixtures/plans/plan_response.json create mode 100644 test/fixtures/recipes/my_recipe_pagination_response.json create mode 100644 test/fixtures/recipes/my_recipe_response.json create mode 100644 test/fixtures/registration/location_response.json diff --git a/lib/features/chat/models/chat_room_pagination_model.dart b/lib/features/chat/models/chat_room_pagination_model.dart index 19de28c3..52cb9f7c 100644 --- a/lib/features/chat/models/chat_room_pagination_model.dart +++ b/lib/features/chat/models/chat_room_pagination_model.dart @@ -31,18 +31,18 @@ abstract class ChatRoom with _$ChatRoom { } ChatMessageModel? parseLastMessage(dynamic json) { - if (json is List) { + if (json == null || json is List) { return null; } - return ChatMessageModel.fromJson(json); + if (json is Map) { + return ChatMessageModel.fromJson(json); + } + return null; } @freezed abstract class Users with _$Users { - const factory Users({ - @JsonKey(name: "from_chat_user") required ChatUser fromChatUser, - @JsonKey(name: "to_chat_user") required ChatUser toChatUser, - }) = _Users; + const factory Users({@JsonKey(name: "from_chat_user") required ChatUser fromChatUser, @JsonKey(name: "to_chat_user") required ChatUser toChatUser}) = _Users; factory Users.fromJson(Map json) => _$UsersFromJson(json); } diff --git a/test/features/auth/services/auth_service_test.dart b/test/features/auth/services/auth_service_test.dart new file mode 100644 index 00000000..503de320 --- /dev/null +++ b/test/features/auth/services/auth_service_test.dart @@ -0,0 +1,70 @@ +import 'package:eatvio_app/features/auth/models/credentials_model.dart'; +import 'package:eatvio_app/features/auth/models/oauth_login_request.dart'; +import 'package:eatvio_app/features/auth/models/oauth_model.dart'; +import 'package:eatvio_app/features/auth/models/token_model.dart'; +import 'package:eatvio_app/features/auth/services/auth_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import '../../../fixtures/fixture_reader.dart'; +import 'auth_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('AuthService', () { + late MockAuthService mockAuthService; + + setUp(() { + mockAuthService = MockAuthService(); + }); + + test('getTokenByCredentials - возвращает токен по учетным данным', () async { + final tokenJson = FixtureReader.readAsMap('auth/token_response.json'); + final expectedToken = TokenModel.fromJson(tokenJson); + final credentialsJson = FixtureReader.readAsMap('auth/login_credentials.json'); + final credentials = CredentialsModel.fromJson(credentialsJson); + + when(mockAuthService.getTokenByCredentials(credentials: credentials)) + .thenAnswer((_) async => expectedToken); + + final result = await mockAuthService.getTokenByCredentials(credentials: credentials); + + expect(result, isA()); + expect(result.token, 'test_token_12345'); + verify(mockAuthService.getTokenByCredentials(credentials: credentials)).called(1); + }); + + test('signInViaSocialMedia - возвращает токен при входе через соцсети', () async { + final tokenJson = FixtureReader.readAsMap('auth/token_response.json'); + final expectedToken = TokenModel.fromJson(tokenJson); + final oauthJson = FixtureReader.readAsMap('auth/oauth_signin_request.json'); + final oauthRequest = OAuthLoginRequest.fromJson(oauthJson); + + when(mockAuthService.signInViaSocialMedia(body: oauthRequest)) + .thenAnswer((_) async => expectedToken); + + final result = await mockAuthService.signInViaSocialMedia(body: oauthRequest); + + expect(result, isA()); + expect(result.token, 'test_token_12345'); + verify(mockAuthService.signInViaSocialMedia(body: oauthRequest)).called(1); + }); + + test('signUpViaSocialMedia - возвращает данные при регистрации через соцсети', () async { + final expectedResponse = {'success': true, 'message': 'User registered'}; + final oauthJson = FixtureReader.readAsMap('auth/oauth_signup_request.json'); + final oauthModel = OAuthModel.fromJson(oauthJson); + + when(mockAuthService.signUpViaSocialMedia(body: oauthModel)) + .thenAnswer((_) async => expectedResponse); + + final result = await mockAuthService.signUpViaSocialMedia(body: oauthModel); + + expect(result, isA>()); + expect(result['success'], true); + verify(mockAuthService.signUpViaSocialMedia(body: oauthModel)).called(1); + }); + }); +} + diff --git a/test/features/auth/services/reset_password_service_test.dart b/test/features/auth/services/reset_password_service_test.dart new file mode 100644 index 00000000..bf5fef76 --- /dev/null +++ b/test/features/auth/services/reset_password_service_test.dart @@ -0,0 +1,57 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/auth/services/reset_password_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:retrofit/retrofit.dart'; + +import '../../../fixtures/fixture_reader.dart'; +import 'reset_password_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('ResetPasswordService', () { + late MockResetPasswordService mockResetPasswordService; + + setUp(() { + mockResetPasswordService = MockResetPasswordService(); + }); + + test('sendEmailCodeForPasswordChange - отправляет код на email', () async { + final requestJson = FixtureReader.readAsMap('auth/reset_password_request.json'); + final expectedResponse = HttpResponse(requestJson, Response( + data: requestJson, + statusCode: 200, + requestOptions: RequestOptions(path: '/api/send_password_reset_code'), + )); + + when(mockResetPasswordService.sendEmailCodeForPasswordChange(data: requestJson)) + .thenAnswer((_) async => expectedResponse); + + final result = await mockResetPasswordService.sendEmailCodeForPasswordChange(data: requestJson); + + expect(result, isA()); + expect(result.response.statusCode, 200); + verify(mockResetPasswordService.sendEmailCodeForPasswordChange(data: requestJson)).called(1); + }); + + test('confirmPasswordChange - подтверждает смену пароля', () async { + final requestJson = FixtureReader.readAsMap('auth/reset_password_request.json'); + final expectedResponse = HttpResponse({'success': true}, Response( + data: {'success': true}, + statusCode: 200, + requestOptions: RequestOptions(path: '/api/confirm_password_reset_code'), + )); + + when(mockResetPasswordService.confirmPasswordChange(data: requestJson)) + .thenAnswer((_) async => expectedResponse); + + final result = await mockResetPasswordService.confirmPasswordChange(data: requestJson); + + expect(result, isA()); + expect(result.response.statusCode, 200); + verify(mockResetPasswordService.confirmPasswordChange(data: requestJson)).called(1); + }); + }); +} + diff --git a/test/features/blog_post_create/services/blog_post_service_test.dart b/test/features/blog_post_create/services/blog_post_service_test.dart new file mode 100644 index 00000000..cbfcef01 --- /dev/null +++ b/test/features/blog_post_create/services/blog_post_service_test.dart @@ -0,0 +1,53 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/blog_post_create/services/blog_post_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'blog_post_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('BlogPostService', () { + late MockBlogPostService mockBlogPostService; + + setUp(() { + mockBlogPostService = MockBlogPostService(); + }); + + test('createBlogPost - создает пост блога', () async { + final formData = FormData.fromMap({}); + + when(mockBlogPostService.createBlogPost(formData: formData)) + .thenAnswer((_) async => Future.value()); + + await mockBlogPostService.createBlogPost(formData: formData); + + verify(mockBlogPostService.createBlogPost(formData: formData)).called(1); + }); + + test('updateBlogPost - обновляет пост блога', () async { + const id = 1; + final formData = FormData.fromMap({}); + + when(mockBlogPostService.updateBlogPost(id: id, formData: formData)) + .thenAnswer((_) async => Future.value()); + + await mockBlogPostService.updateBlogPost(id: id, formData: formData); + + verify(mockBlogPostService.updateBlogPost(id: id, formData: formData)).called(1); + }); + + test('deleteBlogPost - удаляет пост блога', () async { + const id = 1; + + when(mockBlogPostService.deleteBlogPost(id: id)) + .thenAnswer((_) async => Future.value()); + + await mockBlogPostService.deleteBlogPost(id: id); + + verify(mockBlogPostService.deleteBlogPost(id: id)).called(1); + }); + }); +} + diff --git a/test/features/calendar/services/calendar_service_test.dart b/test/features/calendar/services/calendar_service_test.dart new file mode 100644 index 00000000..a410893e --- /dev/null +++ b/test/features/calendar/services/calendar_service_test.dart @@ -0,0 +1,34 @@ +import 'package:eatvio_app/features/calendar/models/calendar_model.dart'; +import 'package:eatvio_app/features/calendar/services/calendar_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import '../../../fixtures/fixture_reader.dart'; +import 'calendar_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('CalendarService', () { + late MockCalendarService mockCalendarService; + + setUp(() { + mockCalendarService = MockCalendarService(); + }); + + test('getCalendar - возвращает календарь', () async { + final json = FixtureReader.readAsList('calendar/calendar_response.json'); + final expectedCalendar = json.map((item) => CalendarModel.fromJson(item as Map)).toList(); + + when(mockCalendarService.getCalendar()) + .thenAnswer((_) async => expectedCalendar); + + final result = await mockCalendarService.getCalendar(); + + expect(result, isA>()); + expect(result.length, 2); + verify(mockCalendarService.getCalendar()).called(1); + }); + }); +} + diff --git a/test/features/cancel_plan_bottom_sheet/service/cancel_plan_service_test.dart b/test/features/cancel_plan_bottom_sheet/service/cancel_plan_service_test.dart new file mode 100644 index 00000000..61419b96 --- /dev/null +++ b/test/features/cancel_plan_bottom_sheet/service/cancel_plan_service_test.dart @@ -0,0 +1,39 @@ +import 'package:eatvio_app/features/cancel_plan_bottom_sheet/models/cancelation_model.dart'; +import 'package:eatvio_app/features/cancel_plan_bottom_sheet/service/cancel_plan_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'cancel_plan_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('CancelPlanService', () { + late MockCancelPlanService mockCancelPlanService; + + setUp(() { + mockCancelPlanService = MockCancelPlanService(); + }); + + test('cancelChosenPlan - отменяет выбранный план', () async { + const id = 1; + final cancelationModel = CancelationModel(description: 'Test reason', price: 100); + + when(mockCancelPlanService.cancelChosenPlan(id: id, body: cancelationModel)).thenAnswer((_) async => Future.value()); + + await mockCancelPlanService.cancelChosenPlan(id: id, body: cancelationModel); + + verify(mockCancelPlanService.cancelChosenPlan(id: id, body: cancelationModel)).called(1); + }); + + test('cancelChosenPlan - отменяет план без причины', () async { + const id = 1; + + when(mockCancelPlanService.cancelChosenPlan(id: id, body: null)).thenAnswer((_) async => Future.value()); + + await mockCancelPlanService.cancelChosenPlan(id: id, body: null); + + verify(mockCancelPlanService.cancelChosenPlan(id: id, body: null)).called(1); + }); + }); +} diff --git a/test/features/chat/models/chat_message_model_test.dart b/test/features/chat/models/chat_message_model_test.dart index b79b7deb..3720b9c6 100644 --- a/test/features/chat/models/chat_message_model_test.dart +++ b/test/features/chat/models/chat_message_model_test.dart @@ -1,5 +1,6 @@ import 'package:eatvio_app/features/chat/models/chat_message_model.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../../../fixtures/fixture_reader.dart'; void main() { group('ChatMessageModel', () { @@ -23,22 +24,24 @@ void main() { }); test('fromJson создает ChatMessageModel из JSON', () { - final json = { - 'id': 1, - 'data': 'Test message', - 'media_data': null, - 'author_id': 123, - 'updated_at': '2024-01-01T00:00:00Z', - 'read_by_to_user': false, - 'is_author_message_auth_user': true, - 'room_id': 'room-1', - }; + final json = FixtureReader.readAsMap('chat/chat_message_response.json'); final model = ChatMessageModel.fromJson(json); expect(model.id, 1); expect(model.data, 'Test message'); - expect(model.authorId, 123); + expect(model.authorId, 1); + }); + + test('fromJson создает ChatMessageModel с медиа из JSON', () { + final json = FixtureReader.readAsMap('chat/chat_message_with_media_response.json'); + + final model = ChatMessageModel.fromJson(json); + + expect(model.id, 2); + expect(model.data, 'Message with attachment'); + expect(model.mediaData, isNotNull); + expect(model.mediaData!.length, 1); }); }); } diff --git a/test/features/chat/models/chat_messages_model_test.dart b/test/features/chat/models/chat_messages_model_test.dart index 9f4d7674..2305b3e7 100644 --- a/test/features/chat/models/chat_messages_model_test.dart +++ b/test/features/chat/models/chat_messages_model_test.dart @@ -2,6 +2,7 @@ import 'package:eatvio_app/features/chat/models/chat_message_model.dart'; import 'package:eatvio_app/features/chat/models/chat_meta_model.dart'; import 'package:eatvio_app/features/chat/models/chat_messages_model.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../../../fixtures/fixture_reader.dart'; void main() { group('ChatMessagesModel', () { @@ -19,10 +20,7 @@ void main() { const meta = ChatMetaModel(lastPage: 1); - final model = ChatMessagesModel( - messagesList: [message], - meta: meta, - ); + final model = ChatMessagesModel(messagesList: [message], meta: meta); expect(model.messagesList.length, 1); expect(model.messagesList.first.id, 1); @@ -30,30 +28,14 @@ void main() { }); test('fromJson создает ChatMessagesModel из JSON', () { - final json = { - 'data': [ - { - 'id': 1, - 'data': 'Test message', - 'media_data': null, - 'author_id': 123, - 'updated_at': '2024-01-01T00:00:00Z', - 'read_by_to_user': false, - 'is_author_message_auth_user': true, - 'room_id': 'room-1', - } - ], - 'meta': { - 'last_page': 1, - }, - }; + final json = FixtureReader.readAsMap('chat/chat_messages_response.json'); final model = ChatMessagesModel.fromJson(json); - expect(model.messagesList.length, 1); + expect(model.messagesList.length, 2); expect(model.messagesList.first.id, 1); + expect(model.messagesList.first.data, 'First message'); expect(model.meta.lastPage, 1); }); }); } - diff --git a/test/features/chat/models/chat_room_model_test.dart b/test/features/chat/models/chat_room_model_test.dart index ad66150b..c561972d 100644 --- a/test/features/chat/models/chat_room_model_test.dart +++ b/test/features/chat/models/chat_room_model_test.dart @@ -2,6 +2,7 @@ import 'package:eatvio_app/features/chat/models/chat_room_model.dart'; import 'package:eatvio_app/features/chat/models/chat_room_settings_model.dart'; import 'package:eatvio_app/features/chat/models/chat_user_model.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../../../fixtures/fixture_reader.dart'; void main() { group('ChatRoomModel', () { @@ -41,34 +42,12 @@ void main() { }); test('fromJson создает ChatRoomModel из JSON', () { - final json = { - 'id': 'room-1', - 'chat_room_setting': { - 'room_name': 'Room Name', - 'state': 'active', - }, - 'users': { - 'from_chat_user': { - 'id': 1, - 'name': 'Sender', - 'slug': 'sender', - 'profile_photo_url': 'https://example.com/sender.jpg', - }, - 'to_chat_user': { - 'id': 2, - 'name': 'Receiver', - 'slug': 'receiver', - 'profile_photo_url': 'https://example.com/receiver.jpg', - }, - }, - 'chosen_plan_id': 1, - 'chosen_plan': null, - }; + final json = FixtureReader.readAsMap('chat/chat_room_response.json'); final model = ChatRoomModel.fromJson(json); - expect(model.id, 'room-1'); - expect(model.chosenPlanId, 1); + expect(model.id, 'chat-1'); + expect(model.chosenPlanId, null); expect(model.users.sender.id, 1); expect(model.users.receiver.id, 2); }); @@ -76,22 +55,10 @@ void main() { group('Users', () { test('fromJson создает Users из JSON', () { - final json = { - 'from_chat_user': { - 'id': 1, - 'name': 'Sender', - 'slug': 'sender', - 'profile_photo_url': 'https://example.com/sender.jpg', - }, - 'to_chat_user': { - 'id': 2, - 'name': 'Receiver', - 'slug': 'receiver', - 'profile_photo_url': 'https://example.com/receiver.jpg', - }, - }; + final roomJson = FixtureReader.readAsMap('chat/chat_room_response.json'); + final usersJson = roomJson['users'] as Map; - final users = Users.fromJson(json); + final users = Users.fromJson(usersJson); expect(users.sender.id, 1); expect(users.receiver.id, 2); diff --git a/test/features/chat/models/chat_room_pagination_model_test.dart b/test/features/chat/models/chat_room_pagination_model_test.dart index 7e9a292f..8b50eba4 100644 --- a/test/features/chat/models/chat_room_pagination_model_test.dart +++ b/test/features/chat/models/chat_room_pagination_model_test.dart @@ -1,6 +1,7 @@ import 'package:eatvio_app/core/models/pagination_model.dart'; import 'package:eatvio_app/features/chat/models/chat_room_pagination_model.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../../../fixtures/fixture_reader.dart'; void main() { group('ChatRoomPaginationModel', () { @@ -46,54 +47,12 @@ void main() { }); test('fromJson создает ChatRoomPaginationModel из JSON', () { - final json = { - 'data': [ - { - 'id': 'room-1', - 'last_message': { - 'id': 1, - 'data': 'Test message', - 'media_data': null, - 'author_id': 123, - 'updated_at': '2024-01-01T00:00:00Z', - 'read_by_to_user': false, - 'is_author_message_auth_user': true, - 'room_id': 'room-1', - }, - 'users': { - 'from_chat_user': { - 'id': 1, - 'name': 'User 1', - 'profile_photo_path': null, - 'profile_photo_url': 'https://example.com/user1.jpg', - }, - 'to_chat_user': { - 'id': 2, - 'name': 'User 2', - 'profile_photo_path': null, - 'profile_photo_url': 'https://example.com/user2.jpg', - }, - }, - 'unread_messages_count': 5, - 'chosen_plan': null, - }, - ], - 'number_of_unread_chat_rooms': 1, - 'meta': { - 'current_page': 1, - 'from': 1, - 'last_page': 1, - 'links': [], - 'per_page': 10, - 'to': 1, - 'total': 1, - }, - }; + final json = FixtureReader.readAsMap('chat/chat_room_pagination_response.json'); final pagination = ChatRoomPaginationModel.fromJson(json); - expect(pagination.data.length, 1); - expect(pagination.data.first.id, 'room-1'); + expect(pagination.data.length, 2); + expect(pagination.data.first.id, 'chat-1'); expect(pagination.unreadChatsCount, 1); }); }); @@ -106,16 +65,7 @@ void main() { }); test('parseLastMessage создает ChatMessageModel из Map', () { - final json = { - 'id': 1, - 'data': 'Test message', - 'media_data': null, - 'author_id': 123, - 'updated_at': '2024-01-01T00:00:00Z', - 'read_by_to_user': false, - 'is_author_message_auth_user': true, - 'room_id': 'room-1', - }; + final json = FixtureReader.readAsMap('chat/chat_message_response.json'); final result = parseLastMessage(json); @@ -127,39 +77,12 @@ void main() { group('ChatRoom', () { test('fromJson создает ChatRoom из JSON', () { - final json = { - 'id': 'room-1', - 'last_message': { - 'id': 1, - 'data': 'Test message', - 'media_data': null, - 'author_id': 123, - 'updated_at': '2024-01-01T00:00:00Z', - 'read_by_to_user': false, - 'is_author_message_auth_user': true, - 'room_id': 'room-1', - }, - 'users': { - 'from_chat_user': { - 'id': 1, - 'name': 'User 1', - 'profile_photo_path': null, - 'profile_photo_url': 'https://example.com/user1.jpg', - }, - 'to_chat_user': { - 'id': 2, - 'name': 'User 2', - 'profile_photo_path': null, - 'profile_photo_url': 'https://example.com/user2.jpg', - }, - }, - 'unread_messages_count': 5, - 'chosen_plan': null, - }; + final paginationJson = FixtureReader.readAsMap('chat/chat_room_pagination_response.json'); + final chatRoomJson = (paginationJson['data'] as List).first as Map; - final chatRoom = ChatRoom.fromJson(json); + final chatRoom = ChatRoom.fromJson(chatRoomJson); - expect(chatRoom.id, 'room-1'); + expect(chatRoom.id, 'chat-1'); expect(chatRoom.unreadMessagesCount, 5); expect(chatRoom.lastMessage, isNotNull); }); @@ -194,22 +117,11 @@ void main() { group('Users', () { test('fromJson создает Users из JSON', () { - final json = { - 'from_chat_user': { - 'id': 1, - 'name': 'User 1', - 'profile_photo_path': null, - 'profile_photo_url': 'https://example.com/user1.jpg', - }, - 'to_chat_user': { - 'id': 2, - 'name': 'User 2', - 'profile_photo_path': null, - 'profile_photo_url': 'https://example.com/user2.jpg', - }, - }; + final paginationJson = FixtureReader.readAsMap('chat/chat_room_pagination_response.json'); + final chatRoomJson = (paginationJson['data'] as List).first as Map; + final usersJson = chatRoomJson['users'] as Map; - final users = Users.fromJson(json); + final users = Users.fromJson(usersJson); expect(users.fromChatUser.id, 1); expect(users.toChatUser.id, 2); @@ -218,14 +130,12 @@ void main() { group('ChatUser', () { test('fromJson создает ChatUser из JSON', () { - final json = { - 'id': 1, - 'name': 'User 1', - 'profile_photo_path': null, - 'profile_photo_url': 'https://example.com/user1.jpg', - }; + final paginationJson = FixtureReader.readAsMap('chat/chat_room_pagination_response.json'); + final chatRoomJson = (paginationJson['data'] as List).first as Map; + final usersJson = chatRoomJson['users'] as Map; + final chatUserJson = usersJson['from_chat_user'] as Map; - final chatUser = ChatUser.fromJson(json); + final chatUser = ChatUser.fromJson(chatUserJson); expect(chatUser.id, 1); expect(chatUser.name, 'User 1'); diff --git a/test/features/chat/repositories/chat_repository_test.dart b/test/features/chat/repositories/chat_repository_test.dart index 80d6c35f..828c0e38 100644 --- a/test/features/chat/repositories/chat_repository_test.dart +++ b/test/features/chat/repositories/chat_repository_test.dart @@ -3,23 +3,18 @@ import 'package:dio/dio.dart'; import 'package:eatvio_app/core/models/pagination_model.dart'; import 'package:eatvio_app/features/chat/models/chat_message_model.dart'; import 'package:eatvio_app/features/chat/models/chat_messages_model.dart'; -import 'package:eatvio_app/features/chat/models/chat_meta_model.dart'; import 'package:eatvio_app/features/chat/models/chat_room_model.dart' as chat_room; import 'package:eatvio_app/features/chat/models/chat_room_pagination_model.dart'; -import 'package:eatvio_app/features/chat/models/chat_room_settings_model.dart'; -import 'package:eatvio_app/features/chat/models/chat_user_model.dart'; import 'package:eatvio_app/features/chat/models/payment_model.dart'; import 'package:eatvio_app/features/chat/models/plan_complain_model.dart'; import 'package:eatvio_app/features/chat/repositories/chat_repository.dart'; import 'package:eatvio_app/features/chat/services/chat_service.dart'; -import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart'; import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart'; -import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; -import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:retrofit/retrofit.dart'; +import '../../../fixtures/fixture_reader.dart'; import 'chat_repository_test.mocks.dart'; @GenerateNiceMocks([MockSpec()]) @@ -35,16 +30,8 @@ void main() { }); test('emitNewMessageToChats - эмитит новое сообщение в поток', () async { - final message = ChatMessageModel( - id: 1, - data: 'Test message', - mediaData: null, - authorId: 1, - updatedAt: DateTime.now(), - isRead: false, - isCurrentUserAuthor: true, - roomId: 'room-1', - ); + final messageFixture = FixtureReader.readAsMap('chat/chat_message_response.json'); + final message = ChatMessageModel.fromJson(messageFixture); chatRepository.emitNewMessageToChats(message); @@ -123,29 +110,9 @@ void main() { }); test('getChatRoom - получает комнату чата по UUID', () async { - const uuid = 'room-uuid-123'; - const expectedRoom = chat_room.ChatRoomModel( - id: uuid, - chatRoomSettings: ChatRoomSettingsModel( - name: 'Test Room', - state: 'active', - ), - users: chat_room.Users( - sender: ChatUserModel( - id: 1, - slug: 'user-1', - name: 'User 1', - profilePhotoUrl: null, - ), - receiver: ChatUserModel( - id: 2, - slug: 'user-2', - name: 'User 2', - profilePhotoUrl: null, - ), - ), - chosenPlanId: null, - ); + const uuid = 'chat-1'; + final roomFixture = FixtureReader.readAsMap('chat/chat_room_response.json'); + final expectedRoom = chat_room.ChatRoomModel.fromJson(roomFixture); when(mockChatService.getChatRoom(uuid: uuid)) .thenAnswer((_) async => expectedRoom); @@ -170,19 +137,8 @@ void main() { }); test('getChatRooms - получает список комнат чата', () async { - const expectedPagination = ChatRoomPaginationModel( - data: [], - unreadChatsCount: 0, - meta: Meta( - currentPage: 1, - from: null, - lastPage: 1, - links: [], - perPage: 10, - to: null, - total: 0, - ), - ); + final paginationFixture = FixtureReader.readAsMap('chat/chat_room_pagination_response.json'); + final expectedPagination = ChatRoomPaginationModel.fromJson(paginationFixture); when(mockChatService.getChatRooms(query: null, page: 1)) .thenAnswer((_) async => expectedPagination); @@ -190,24 +146,14 @@ void main() { final result = await chatRepository.getChatRooms(); expect(result, isA()); + expect(result.data.length, 2); verify(mockChatService.getChatRooms(query: null, page: 1)).called(1); }); test('getChatRooms - получает список комнат с запросом', () async { const query = 'test query'; - const expectedPagination = ChatRoomPaginationModel( - data: [], - unreadChatsCount: 0, - meta: Meta( - currentPage: 1, - from: null, - lastPage: 1, - links: [], - perPage: 10, - to: null, - total: 0, - ), - ); + final paginationFixture = FixtureReader.readAsMap('chat/chat_room_pagination_response.json'); + final expectedPagination = ChatRoomPaginationModel.fromJson(paginationFixture); when(mockChatService.getChatRooms(query: query, page: 1)) .thenAnswer((_) async => expectedPagination); @@ -243,23 +189,10 @@ void main() { }); test('getChatMessages - получает сообщения чата', () async { - const chatId = 'chat-id-123'; + const chatId = 'chat-1'; const page = 1; - final expectedMessages = ChatMessagesModel( - messagesList: [ - ChatMessageModel( - id: 1, - data: 'Message 1', - mediaData: null, - authorId: 1, - updatedAt: DateTime.now(), - isRead: false, - isCurrentUserAuthor: true, - roomId: chatId, - ), - ], - meta: const ChatMetaModel(lastPage: 1), - ); + final messagesFixture = FixtureReader.readAsMap('chat/chat_messages_response.json'); + final expectedMessages = ChatMessagesModel.fromJson(messagesFixture); when(mockChatService.getChatMessages(id: chatId, page: page)) .thenAnswer((_) async => expectedMessages); @@ -267,34 +200,14 @@ void main() { final result = await chatRepository.getChatMessages(chatId, page); expect(result, isA()); - expect(result.messagesList.length, 1); + expect(result.messagesList.length, 2); verify(mockChatService.getChatMessages(id: chatId, page: page)).called(1); }); test('getChatRoomIdByUserSlug - получает комнату по slug пользователя', () async { - const slug = 'user-slug'; - const expectedRoom = chat_room.ChatRoomModel( - id: 'room-id', - chatRoomSettings: ChatRoomSettingsModel( - name: 'Test Room', - state: 'active', - ), - users: chat_room.Users( - sender: ChatUserModel( - id: 1, - slug: slug, - name: 'User', - profilePhotoUrl: null, - ), - receiver: ChatUserModel( - id: 2, - slug: 'other-user', - name: 'Other User', - profilePhotoUrl: null, - ), - ), - chosenPlanId: null, - ); + const slug = 'user-1'; + final roomFixture = FixtureReader.readAsMap('chat/chat_room_response.json'); + final expectedRoom = chat_room.ChatRoomModel.fromJson(roomFixture); when(mockChatService.getChatRoomIdByUserSlug(user: slug)) .thenAnswer((_) async => expectedRoom); @@ -347,7 +260,8 @@ void main() { test('getPaymentLink - получает ссылку на оплату', () async { const planId = 123; - final expectedPayment = PaymentModel(paymentUrl: 'https://payment.url'); + final paymentFixture = FixtureReader.readAsMap('chat/payment_response.json'); + final expectedPayment = PaymentModel.fromJson(paymentFixture); when(mockChatService.getPaymentLink(id: planId)) .thenAnswer((_) async => expectedPayment); @@ -355,49 +269,14 @@ void main() { final result = await chatRepository.getPaymentLink(id: planId); expect(result, isA()); - expect(result.paymentUrl, 'https://payment.url'); + expect(result.paymentUrl, 'https://example.com/checkout/payment-123'); verify(mockChatService.getPaymentLink(id: planId)).called(1); }); test('getChosenPlan - получает выбранный план', () async { - const planId = 123; - final expectedPlan = ChosenPlanModel( - id: planId, - optionType: 'standard', - startDate: DateTime.now(), - chosenPlanState: ChosenPlanStateEnum.stateInCoordination, - chatId: 'chat-id', - consultantId: 1, - plan: const PlanModel( - id: 456, - slug: 'plan-slug', - name: 'Test Plan', - image: '', - duration: 30, - state: 'active', - type: PlanType( - fit: true, - slim: false, - behavior: false, - wellness: false, - ), - details: '', - packetsCount: 1, - author: Author( - authorSlug: 'author', - authorName: 'Author', - authorProfileIcon: '', - authorIsMe: false, - ), - totalLikes: 0, - totalViews: 0, - totalComments: 0, - isFavorite: false, - minPriceOfOptions: 0.0, - maxPriceOfOptions: 100.0, - wasLikedByMe: false, - ), - ); + const planId = 1; + final chosenPlanFixture = FixtureReader.readAsMap('chat/chosen_plan_response.json'); + final expectedPlan = ChosenPlanModel.fromJson(chosenPlanFixture); when(mockChatService.getChosenPlan(id: planId)) .thenAnswer((_) async => expectedPlan); @@ -422,7 +301,8 @@ void main() { test('complainAboutConsultation - отправляет жалобу на консультацию', () async { const planId = 123; - final complainModel = PlanComplainModel(description: 'Test complaint'); + final complainFixture = FixtureReader.readAsMap('chat/plan_complain_response.json'); + final complainModel = PlanComplainModel.fromJson(complainFixture); when(mockChatService.complainAboutConsultation(id: planId, body: complainModel)) .thenAnswer((_) async => Future.value()); diff --git a/test/features/chat/services/chat_service_test.dart b/test/features/chat/services/chat_service_test.dart index d70f47fc..76fb32bf 100644 --- a/test/features/chat/services/chat_service_test.dart +++ b/test/features/chat/services/chat_service_test.dart @@ -1,23 +1,16 @@ import 'package:dio/dio.dart'; -import 'package:eatvio_app/core/models/pagination_model.dart'; -import 'package:eatvio_app/features/chat/models/chat_message_model.dart'; import 'package:eatvio_app/features/chat/models/chat_messages_model.dart'; -import 'package:eatvio_app/features/chat/models/chat_meta_model.dart'; import 'package:eatvio_app/features/chat/models/chat_room_model.dart' as chat_room; import 'package:eatvio_app/features/chat/models/chat_room_pagination_model.dart'; -import 'package:eatvio_app/features/chat/models/chat_room_settings_model.dart'; -import 'package:eatvio_app/features/chat/models/chat_user_model.dart'; import 'package:eatvio_app/features/chat/models/payment_model.dart'; import 'package:eatvio_app/features/chat/models/plan_complain_model.dart'; import 'package:eatvio_app/features/chat/services/chat_service.dart'; -import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart'; import 'package:eatvio_app/features/plans/models/chosen_plan_model.dart'; -import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; -import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:retrofit/retrofit.dart'; +import '../../../fixtures/fixture_reader.dart'; import 'chat_service_test.mocks.dart'; @GenerateNiceMocks([MockSpec()]) @@ -30,48 +23,24 @@ void main() { }); test('getChatRooms - возвращает список комнат чата', () async { - const expectedPagination = ChatRoomPaginationModel( - data: [], - unreadChatsCount: 0, - meta: Meta( - currentPage: 1, - from: null, - lastPage: 1, - links: [], - perPage: 10, - to: null, - total: 0, - ), - ); + final paginationFixture = FixtureReader.readAsMap('chat/chat_room_pagination_response.json'); + final expectedPagination = ChatRoomPaginationModel.fromJson(paginationFixture); - when(mockChatService.getChatRooms(query: null, page: 1)) - .thenAnswer((_) async => expectedPagination); + when(mockChatService.getChatRooms(query: null, page: 1)).thenAnswer((_) async => expectedPagination); final result = await mockChatService.getChatRooms(query: null, page: 1); expect(result, isA()); - expect(result.data.length, 0); + expect(result.data.length, 2); verify(mockChatService.getChatRooms(query: null, page: 1)).called(1); }); test('getChatRooms - возвращает список комнат с запросом', () async { const query = 'test query'; - const expectedPagination = ChatRoomPaginationModel( - data: [], - unreadChatsCount: 0, - meta: Meta( - currentPage: 1, - from: null, - lastPage: 1, - links: [], - perPage: 10, - to: null, - total: 0, - ), - ); + final paginationFixture = FixtureReader.readAsMap('chat/chat_room_pagination_response.json'); + final expectedPagination = ChatRoomPaginationModel.fromJson(paginationFixture); - when(mockChatService.getChatRooms(query: query, page: 1)) - .thenAnswer((_) async => expectedPagination); + when(mockChatService.getChatRooms(query: query, page: 1)).thenAnswer((_) async => expectedPagination); final result = await mockChatService.getChatRooms(query: query, page: 1); @@ -80,32 +49,11 @@ void main() { }); test('getChatRoom - возвращает комнату чата по UUID', () async { - const uuid = 'room-uuid-123'; - const expectedRoom = chat_room.ChatRoomModel( - id: uuid, - chatRoomSettings: ChatRoomSettingsModel( - name: 'Test Room', - state: 'active', - ), - users: chat_room.Users( - sender: ChatUserModel( - id: 1, - slug: 'user-1', - name: 'User 1', - profilePhotoUrl: null, - ), - receiver: ChatUserModel( - id: 2, - slug: 'user-2', - name: 'User 2', - profilePhotoUrl: null, - ), - ), - chosenPlanId: null, - ); + const uuid = 'chat-1'; + final roomFixture = FixtureReader.readAsMap('chat/chat_room_response.json'); + final expectedRoom = chat_room.ChatRoomModel.fromJson(roomFixture); - when(mockChatService.getChatRoom(uuid: uuid)) - .thenAnswer((_) async => expectedRoom); + when(mockChatService.getChatRoom(uuid: uuid)).thenAnswer((_) async => expectedRoom); final result = await mockChatService.getChatRoom(uuid: uuid); @@ -119,84 +67,34 @@ void main() { const data = 'Test message'; const socketId = 'socket-id-123'; - when(mockChatService.sendMessage( - slug: slug, - data: data, - mediaData: null, - socketId: socketId, - )).thenAnswer((_) async => Future.value()); + when(mockChatService.sendMessage(slug: slug, data: data, mediaData: null, socketId: socketId)).thenAnswer((_) async => Future.value()); - await mockChatService.sendMessage( - slug: slug, - data: data, - mediaData: null, - socketId: socketId, - ); + await mockChatService.sendMessage(slug: slug, data: data, mediaData: null, socketId: socketId); - verify(mockChatService.sendMessage( - slug: slug, - data: data, - mediaData: null, - socketId: socketId, - )).called(1); + verify(mockChatService.sendMessage(slug: slug, data: data, mediaData: null, socketId: socketId)).called(1); }); test('getChatMessages - возвращает сообщения чата', () async { - const chatId = 'chat-id-123'; + const chatId = 'chat-1'; const page = 1; - final expectedMessages = ChatMessagesModel( - messagesList: [ - ChatMessageModel( - id: 1, - data: 'Message 1', - mediaData: null, - authorId: 1, - updatedAt: DateTime.now(), - isRead: false, - isCurrentUserAuthor: true, - roomId: chatId, - ), - ], - meta: const ChatMetaModel(lastPage: 1), - ); + final messagesFixture = FixtureReader.readAsMap('chat/chat_messages_response.json'); + final expectedMessages = ChatMessagesModel.fromJson(messagesFixture); - when(mockChatService.getChatMessages(id: chatId, page: page)) - .thenAnswer((_) async => expectedMessages); + when(mockChatService.getChatMessages(id: chatId, page: page)).thenAnswer((_) async => expectedMessages); final result = await mockChatService.getChatMessages(id: chatId, page: page); expect(result, isA()); - expect(result.messagesList.length, 1); + expect(result.messagesList.length, 2); verify(mockChatService.getChatMessages(id: chatId, page: page)).called(1); }); test('getChatRoomIdByUserSlug - возвращает комнату по slug пользователя', () async { - const slug = 'user-slug'; - const expectedRoom = chat_room.ChatRoomModel( - id: 'room-id', - chatRoomSettings: ChatRoomSettingsModel( - name: 'Test Room', - state: 'active', - ), - users: chat_room.Users( - sender: ChatUserModel( - id: 1, - slug: slug, - name: 'User', - profilePhotoUrl: null, - ), - receiver: ChatUserModel( - id: 2, - slug: 'other-user', - name: 'Other User', - profilePhotoUrl: null, - ), - ), - chosenPlanId: null, - ); + const slug = 'user-1'; + final roomFixture = FixtureReader.readAsMap('chat/chat_room_response.json'); + final expectedRoom = chat_room.ChatRoomModel.fromJson(roomFixture); - when(mockChatService.getChatRoomIdByUserSlug(user: slug)) - .thenAnswer((_) async => expectedRoom); + when(mockChatService.getChatRoomIdByUserSlug(user: slug)).thenAnswer((_) async => expectedRoom); final result = await mockChatService.getChatRoomIdByUserSlug(user: slug); @@ -208,27 +106,17 @@ void main() { const chatId = 'chat-id-123'; final messageIds = [1, 2, 3]; - when(mockChatService.markMessagesAsRead( - id: chatId, - body: {'messages_ids': messageIds}, - )).thenAnswer((_) async => Future.value()); + when(mockChatService.markMessagesAsRead(id: chatId, body: {'messages_ids': messageIds})).thenAnswer((_) async => Future.value()); - await mockChatService.markMessagesAsRead( - id: chatId, - body: {'messages_ids': messageIds}, - ); + await mockChatService.markMessagesAsRead(id: chatId, body: {'messages_ids': messageIds}); - verify(mockChatService.markMessagesAsRead( - id: chatId, - body: {'messages_ids': messageIds}, - )).called(1); + verify(mockChatService.markMessagesAsRead(id: chatId, body: {'messages_ids': messageIds})).called(1); }); test('cancelChosenPlan - отменяет выбранный план', () async { const planId = 123; - when(mockChatService.cancelChosenPlan(id: planId)) - .thenAnswer((_) async => Future.value()); + when(mockChatService.cancelChosenPlan(id: planId)).thenAnswer((_) async => Future.value()); await mockChatService.cancelChosenPlan(id: planId); @@ -239,8 +127,7 @@ void main() { const planId = 123; final date = {'start_date': '2024-01-15'}; - when(mockChatService.choseStartPlanDate(id: planId, date: date)) - .thenAnswer((_) async => Future.value()); + when(mockChatService.choseStartPlanDate(id: planId, date: date)).thenAnswer((_) async => Future.value()); await mockChatService.choseStartPlanDate(id: planId, date: date); @@ -249,60 +136,24 @@ void main() { test('getPaymentLink - возвращает ссылку на оплату', () async { const planId = 123; - final expectedPayment = PaymentModel(paymentUrl: 'https://payment.url'); + final paymentFixture = FixtureReader.readAsMap('chat/payment_response.json'); + final expectedPayment = PaymentModel.fromJson(paymentFixture); - when(mockChatService.getPaymentLink(id: planId)) - .thenAnswer((_) async => expectedPayment); + when(mockChatService.getPaymentLink(id: planId)).thenAnswer((_) async => expectedPayment); final result = await mockChatService.getPaymentLink(id: planId); expect(result, isA()); - expect(result.paymentUrl, 'https://payment.url'); + expect(result.paymentUrl, 'https://example.com/checkout/payment-123'); verify(mockChatService.getPaymentLink(id: planId)).called(1); }); test('getChosenPlan - возвращает выбранный план', () async { - const planId = 123; - final expectedPlan = ChosenPlanModel( - id: planId, - optionType: 'standard', - startDate: DateTime.now(), - chosenPlanState: ChosenPlanStateEnum.stateInCoordination, - chatId: 'chat-id', - consultantId: 1, - plan: const PlanModel( - id: 456, - slug: 'plan-slug', - name: 'Test Plan', - image: '', - duration: 30, - state: 'active', - type: PlanType( - fit: true, - slim: false, - behavior: false, - wellness: false, - ), - details: '', - packetsCount: 1, - author: Author( - authorSlug: 'author', - authorName: 'Author', - authorProfileIcon: '', - authorIsMe: false, - ), - totalLikes: 0, - totalViews: 0, - totalComments: 0, - isFavorite: false, - minPriceOfOptions: 0.0, - maxPriceOfOptions: 100.0, - wasLikedByMe: false, - ), - ); + const planId = 1; + final chosenPlanFixture = FixtureReader.readAsMap('chat/chosen_plan_response.json'); + final expectedPlan = ChosenPlanModel.fromJson(chosenPlanFixture); - when(mockChatService.getChosenPlan(id: planId)) - .thenAnswer((_) async => expectedPlan); + when(mockChatService.getChosenPlan(id: planId)).thenAnswer((_) async => expectedPlan); final result = await mockChatService.getChosenPlan(id: planId); @@ -314,8 +165,7 @@ void main() { test('finishChosenPlan - завершает выбранный план', () async { const planId = 123; - when(mockChatService.finishChosenPlan(id: planId)) - .thenAnswer((_) async => Future.value()); + when(mockChatService.finishChosenPlan(id: planId)).thenAnswer((_) async => Future.value()); await mockChatService.finishChosenPlan(id: planId); @@ -324,30 +174,22 @@ void main() { test('complainAboutConsultation - отправляет жалобу на консультацию', () async { const planId = 123; - final complainModel = PlanComplainModel(description: 'Test complaint'); + final complainFixture = FixtureReader.readAsMap('chat/plan_complain_response.json'); + final complainModel = PlanComplainModel.fromJson(complainFixture); - when(mockChatService.complainAboutConsultation(id: planId, body: complainModel)) - .thenAnswer((_) async => Future.value()); + when(mockChatService.complainAboutConsultation(id: planId, body: complainModel)).thenAnswer((_) async => Future.value()); await mockChatService.complainAboutConsultation(id: planId, body: complainModel); - verify(mockChatService.complainAboutConsultation(id: planId, body: complainModel)) - .called(1); + verify(mockChatService.complainAboutConsultation(id: planId, body: complainModel)).called(1); }); test('getChatByUserSlug - возвращает HttpResponse', () async { const slug = 'user-slug'; const chatId = 'chat-id-123'; - final response = HttpResponse( - {'id': chatId}, - Response( - requestOptions: RequestOptions(path: ''), - statusCode: 200, - ), - ); + final response = HttpResponse({'id': chatId}, Response(requestOptions: RequestOptions(path: ''), statusCode: 200)); - when(mockChatService.getChatByUserSlug(slug: slug)) - .thenAnswer((_) async => response); + when(mockChatService.getChatByUserSlug(slug: slug)).thenAnswer((_) async => response); final result = await mockChatService.getChatByUserSlug(slug: slug); @@ -357,4 +199,3 @@ void main() { }); }); } - diff --git a/test/features/complaining/services/complaining_service_test.dart b/test/features/complaining/services/complaining_service_test.dart new file mode 100644 index 00000000..2c55e11f --- /dev/null +++ b/test/features/complaining/services/complaining_service_test.dart @@ -0,0 +1,58 @@ +import 'package:eatvio_app/features/complaining/models/complain_model.dart'; +import 'package:eatvio_app/features/complaining/services/complaining_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'complaining_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('ComplainingService', () { + late MockComplainingService mockComplainingService; + + setUp(() { + mockComplainingService = MockComplainingService(); + }); + + test('sendPlanComplain - отправляет жалобу на план', () async { + const slug = 'test-plan'; + const category = 'spam'; + const complainModel = ComplainModel(description: 'Test complaint', tags: []); + + when(mockComplainingService.sendPlanComplain(slug: slug, category: category, body: complainModel)) + .thenAnswer((_) async => Future.value()); + + await mockComplainingService.sendPlanComplain(slug: slug, category: category, body: complainModel); + + verify(mockComplainingService.sendPlanComplain(slug: slug, category: category, body: complainModel)).called(1); + }); + + test('sendRecipeComplain - отправляет жалобу на рецепт', () async { + const slug = 'test-recipe'; + const category = 'spam'; + const complainModel = ComplainModel(description: 'Test complaint', tags: []); + + when(mockComplainingService.sendRecipeComplain(slug: slug, category: category, body: complainModel)) + .thenAnswer((_) async => Future.value()); + + await mockComplainingService.sendRecipeComplain(slug: slug, category: category, body: complainModel); + + verify(mockComplainingService.sendRecipeComplain(slug: slug, category: category, body: complainModel)).called(1); + }); + + test('sendBlogPostsComplain - отправляет жалобу на пост блога', () async { + const id = 1; + const category = 'spam'; + const complainModel = ComplainModel(description: 'Test complaint', tags: []); + + when(mockComplainingService.sendBlogPostsComplain(id: id, category: category, body: complainModel)) + .thenAnswer((_) async => Future.value()); + + await mockComplainingService.sendBlogPostsComplain(id: id, category: category, body: complainModel); + + verify(mockComplainingService.sendBlogPostsComplain(id: id, category: category, body: complainModel)).called(1); + }); + }); +} + diff --git a/test/features/consultant/become_consultant/services/consultant_service_test.dart b/test/features/consultant/become_consultant/services/consultant_service_test.dart new file mode 100644 index 00000000..dd429904 --- /dev/null +++ b/test/features/consultant/become_consultant/services/consultant_service_test.dart @@ -0,0 +1,75 @@ +import 'package:eatvio_app/features/consultant/become_consultant/models/consultant_cert_photo_model.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/models/consultant_profile_model.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/models/consultation_request_model.dart'; +import 'package:eatvio_app/features/consultant/become_consultant/services/consultant_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import '../../../../fixtures/fixture_reader.dart'; +import 'consultant_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('ConsultantService', () { + late MockConsultantService mockConsultantService; + + setUp(() { + mockConsultantService = MockConsultantService(); + }); + + test('getMyRequestStatus - возвращает статус запроса', () async { + const slug = 'test-consultant'; + final json = FixtureReader.readAsMap('consultant/consultation_request.json'); + final expectedRequest = ConsultationRequestModel.fromJson(json); + + when(mockConsultantService.getMyRequestStatus(slug: slug)) + .thenAnswer((_) async => expectedRequest); + + final result = await mockConsultantService.getMyRequestStatus(slug: slug); + + expect(result, isA()); + expect(result.ratingPlace, 12); + verify(mockConsultantService.getMyRequestStatus(slug: slug)).called(1); + }); + + test('getConsultantRequestStatus - возвращает статус запроса консультанта', () async { + const slug = 'test-consultant'; + final json = FixtureReader.readAsMap('consultant/consultation_request.json'); + final expectedRequest = ConsultationRequestModel.fromJson(json); + + when(mockConsultantService.getConsultantRequestStatus(slug: slug)) + .thenAnswer((_) async => expectedRequest); + + final result = await mockConsultantService.getConsultantRequestStatus(slug: slug); + + expect(result, isA()); + verify(mockConsultantService.getConsultantRequestStatus(slug: slug)).called(1); + }); + + test('getConsultantCertPhotos - возвращает фото сертификатов', () async { + final expectedPhotos = []; + + when(mockConsultantService.getConsultantCertPhotos()) + .thenAnswer((_) async => expectedPhotos); + + final result = await mockConsultantService.getConsultantCertPhotos(); + + expect(result, isA>()); + verify(mockConsultantService.getConsultantCertPhotos()).called(1); + }); + + test('consultantRegistration - регистрирует консультанта', () async { + final profileJson = FixtureReader.readAsMap('consultant/consultant_profile_request.json'); + final profile = ConsultantProfileModel.fromJson(profileJson); + + when(mockConsultantService.consultantRegistration(consultantModel: profile)) + .thenAnswer((_) async => Future.value()); + + await mockConsultantService.consultantRegistration(consultantModel: profile); + + verify(mockConsultantService.consultantRegistration(consultantModel: profile)).called(1); + }); + }); +} + diff --git a/test/features/consultant_rating/services/consultant_rating_service_test.dart b/test/features/consultant_rating/services/consultant_rating_service_test.dart new file mode 100644 index 00000000..501b09e8 --- /dev/null +++ b/test/features/consultant_rating/services/consultant_rating_service_test.dart @@ -0,0 +1,55 @@ +import 'package:eatvio_app/features/consultant_rating/models/rating_model.dart'; +import 'package:eatvio_app/features/consultant_rating/models/statistics_model.dart'; +import 'package:eatvio_app/features/consultant_rating/services/consultant_rating_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'consultant_rating_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('ConsultantRatingService', () { + late MockConsultantRatingService mockConsultantRatingService; + + setUp(() { + mockConsultantRatingService = MockConsultantRatingService(); + }); + + test('getConsultantStatistics - возвращает статистику консультанта', () async { + const date = '2024-01-01'; + final expectedStatistics = StatisticsModel( + countReferal: 5, + blogPostsCount: 10, + recipesCount: 15, + dietsCount: 3, + consultationsCount: 20, + qwe: 100, + refLink: 'https://example.com/ref', + ); + + when(mockConsultantRatingService.getConsultantStatistics(date: date)) + .thenAnswer((_) async => expectedStatistics); + + final result = await mockConsultantRatingService.getConsultantStatistics(date: date); + + expect(result, isA()); + expect(result.countReferal, 5); + verify(mockConsultantRatingService.getConsultantStatistics(date: date)).called(1); + }); + + test('getScoreLogs - возвращает логи оценок', () async { + const date = '2024-01-01'; + final expectedLogs = RatingPaginationModel(data: []); + + when(mockConsultantRatingService.getScoreLogs(date: date)) + .thenAnswer((_) async => expectedLogs); + + final result = await mockConsultantRatingService.getScoreLogs(date: date); + + expect(result, isA()); + verify(mockConsultantRatingService.getScoreLogs(date: date)).called(1); + }); + }); +} + diff --git a/test/features/consultations/repositories/consultations_repository_test.dart b/test/features/consultations/repositories/consultations_repository_test.dart index 04e291a0..22cc512c 100644 --- a/test/features/consultations/repositories/consultations_repository_test.dart +++ b/test/features/consultations/repositories/consultations_repository_test.dart @@ -7,6 +7,8 @@ import 'package:eatvio_app/features/finances_and_consultations_archive/models/us import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; +import '../../../fixtures/fixture_reader.dart'; + class MockConsultationService extends Mock implements ConsultationService {} class FakeStatisticModel extends Fake implements StatisticModel {} @@ -69,12 +71,8 @@ void main() { }); test('getStatistic - успешный запрос', () async { - final mockStatistic = StatisticModel( - total: 10, - inProgress: 5, - finished: 3, - canceled: 2, - ); + final json = FixtureReader.readAsMap('consultations/statistic_response.json'); + final mockStatistic = StatisticModel.fromJson(json); when(() => mockService.getStatistics()) .thenAnswer((_) async => mockStatistic); diff --git a/test/features/consultations/services/consultation_service_test.dart b/test/features/consultations/services/consultation_service_test.dart new file mode 100644 index 00000000..e0a5e715 --- /dev/null +++ b/test/features/consultations/services/consultation_service_test.dart @@ -0,0 +1,94 @@ +import 'package:eatvio_app/features/consultations/models/consultation_model.dart'; +import 'package:eatvio_app/features/consultations/services/consultation_service.dart'; +import 'package:eatvio_app/features/finances_and_consultations_archive/models/consultant_finance_model.dart'; +import 'package:eatvio_app/features/finances_and_consultations_archive/models/statistic_model.dart'; +import 'package:eatvio_app/features/finances_and_consultations_archive/models/user_purchases_model.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:dio/dio.dart'; + +import '../../../fixtures/fixture_reader.dart'; +import 'consultation_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('ConsultationService', () { + late ConsultationService consultationService; + late MockDio mockDio; + + setUp(() { + mockDio = MockDio(); + consultationService = ConsultationService(mockDio); + }); + + test('getConsultations - возвращает список консультаций', () async { + final json = FixtureReader.readAsMap('consultations/consultation_pagination_response.json'); + final response = Response( + data: json, + statusCode: 200, + requestOptions: RequestOptions(path: '/api/consultations'), + ); + + when(mockDio.get(any, queryParameters: anyNamed('queryParameters'))) + .thenAnswer((_) async => response); + + final result = await consultationService.getConsultations(); + + expect(result, isA()); + expect(result.data.length, 1); + verify(mockDio.get(any, queryParameters: anyNamed('queryParameters'))).called(1); + }); + + test('getStatistics - возвращает статистику', () async { + final json = FixtureReader.readAsMap('consultations/statistic_response.json'); + final response = Response( + data: json, + statusCode: 200, + requestOptions: RequestOptions(path: '/api/consultations/statistics'), + ); + + when(mockDio.get(any)) + .thenAnswer((_) async => response); + + final result = await consultationService.getStatistics(); + + expect(result, isA()); + expect(result.total, 10); + verify(mockDio.get(any)).called(1); + }); + + test('getConsultantFinances - возвращает финансы консультанта', () async { + final response = Response( + data: {'data': []}, + statusCode: 200, + requestOptions: RequestOptions(path: '/api/finances/my_finances'), + ); + + when(mockDio.get(any, queryParameters: anyNamed('queryParameters'))) + .thenAnswer((_) async => response); + + final result = await consultationService.getConsultantFinances(null, null); + + expect(result, isA>()); + verify(mockDio.get(any, queryParameters: anyNamed('queryParameters'))).called(1); + }); + + test('getUserPurchases - возвращает покупки пользователя', () async { + final response = Response( + data: {'data': []}, + statusCode: 200, + requestOptions: RequestOptions(path: '/api/finances/my_purchases'), + ); + + when(mockDio.get(any, queryParameters: anyNamed('queryParameters'))) + .thenAnswer((_) async => response); + + final result = await consultationService.getUserPurchases(null, null); + + expect(result, isA>()); + verify(mockDio.get(any, queryParameters: anyNamed('queryParameters'))).called(1); + }); + }); +} + diff --git a/test/features/create_diet/services/create_diet_service_test.dart b/test/features/create_diet/services/create_diet_service_test.dart new file mode 100644 index 00000000..63acb21d --- /dev/null +++ b/test/features/create_diet/services/create_diet_service_test.dart @@ -0,0 +1,53 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/create_diet/services/create_diet_service.dart'; +import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:retrofit/retrofit.dart'; + +import 'create_diet_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('CreateDietService', () { + late MockCreateDietService mockCreateDietService; + + setUp(() { + mockCreateDietService = MockCreateDietService(); + }); + + test('createPublishedDiet - создает опубликованную диету', () async { + final formData = FormData.fromMap({}); + const expectedDiet = CreatedDiet(id: 1); + + when(mockCreateDietService.createPublishedDiet(formData: formData)) + .thenAnswer((_) async => expectedDiet); + + final result = await mockCreateDietService.createPublishedDiet(formData: formData); + + expect(result, isA()); + expect(result.id, 1); + verify(mockCreateDietService.createPublishedDiet(formData: formData)).called(1); + }); + + test('getDietPortionsNutrition - возвращает питание порций диеты', () async { + const dietId = 1; + final response = HttpResponse({'data': {}}, Response( + data: {'data': {}}, + statusCode: 200, + requestOptions: RequestOptions(path: '/api/diets/show/$dietId/per_portion_nutritions'), + )); + + when(mockCreateDietService.getDietPortionsNutrition(diet: dietId)) + .thenAnswer((_) async => response); + + final result = await mockCreateDietService.getDietPortionsNutrition(diet: dietId); + + expect(result, isA()); + expect(result.response.statusCode, 200); + verify(mockCreateDietService.getDietPortionsNutrition(diet: dietId)).called(1); + }); + }); +} + diff --git a/test/features/create_plan/services/create_plan_service_test.dart b/test/features/create_plan/services/create_plan_service_test.dart new file mode 100644 index 00000000..88ed8bae --- /dev/null +++ b/test/features/create_plan/services/create_plan_service_test.dart @@ -0,0 +1,30 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/create_plan/services/create_plan_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'create_plan_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('CreatePlanService', () { + late MockCreatePlanService mockCreatePlanService; + + setUp(() { + mockCreatePlanService = MockCreatePlanService(); + }); + + test('createPlan - создает план', () async { + final formData = FormData.fromMap({}); + + when(mockCreatePlanService.createPlan(formData: formData)) + .thenAnswer((_) async => Future.value()); + + await mockCreatePlanService.createPlan(formData: formData); + + verify(mockCreatePlanService.createPlan(formData: formData)).called(1); + }); + }); +} + diff --git a/test/features/create_recipe/services/recipe_service_test.dart b/test/features/create_recipe/services/recipe_service_test.dart new file mode 100644 index 00000000..022eb89a --- /dev/null +++ b/test/features/create_recipe/services/recipe_service_test.dart @@ -0,0 +1,88 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/core/models/pagination_model.dart'; +import 'package:eatvio_app/features/create_recipe/models/recipe_model.dart'; +import 'package:eatvio_app/features/create_recipe/models/recipe_tag_model.dart'; +import 'package:eatvio_app/features/create_recipe/services/recipe_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'recipe_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('CreateRecipeService', () { + late MockCreateRecipeService mockCreateRecipeService; + + setUp(() { + mockCreateRecipeService = MockCreateRecipeService(); + }); + + test('likeRecipe - лайкает рецепт', () async { + const slug = 'test-recipe'; + + when(mockCreateRecipeService.likeRecipe(slug: slug)) + .thenAnswer((_) async => Future.value()); + + await mockCreateRecipeService.likeRecipe(slug: slug); + + verify(mockCreateRecipeService.likeRecipe(slug: slug)).called(1); + }); + + test('getRecipe - возвращает рецепт', () async { + const id = '1'; + const expectedRecipe = RecipeModel( + ingredients: [], + steps: [], + tags: [], + type: 'breakfast', + state: 'published', + title: 'Test Recipe', + description: 'Test Description', + videoUrl: 'https://example.com/video.mp4', + image: 'https://example.com/image.jpg', + totalCookingTime: 30, + activeCookTime: 20, + servings: 4, + energyPerServing: 250, + ); + + when(mockCreateRecipeService.getRecipe(id)) + .thenAnswer((_) async => expectedRecipe); + + final result = await mockCreateRecipeService.getRecipe(id); + + expect(result, isA()); + expect(result.title, 'Test Recipe'); + verify(mockCreateRecipeService.getRecipe(id)).called(1); + }); + + test('getTags - возвращает теги рецептов', () async { + const expectedTags = RecipeTagModel( + data: [], + links: Links(first: '', last: '', prev: null, next: null), + meta: Meta(currentPage: 1, from: null, lastPage: 1, links: [], perPage: 10, to: null, total: 0), + ); + + when(mockCreateRecipeService.getTags()) + .thenAnswer((_) async => expectedTags); + + final result = await mockCreateRecipeService.getTags(); + + expect(result, isA()); + verify(mockCreateRecipeService.getTags()).called(1); + }); + + test('publishRecipe - публикует рецепт', () async { + final formData = FormData.fromMap({}); + + when(mockCreateRecipeService.publishRecipe(formData: formData)) + .thenAnswer((_) async => Future.value()); + + await mockCreateRecipeService.publishRecipe(formData: formData); + + verify(mockCreateRecipeService.publishRecipe(formData: formData)).called(1); + }); + }); +} + diff --git a/test/features/diary/repositories/diary_repository_test.dart b/test/features/diary/repositories/diary_repository_test.dart index 88f73b67..1c39dd6e 100644 --- a/test/features/diary/repositories/diary_repository_test.dart +++ b/test/features/diary/repositories/diary_repository_test.dart @@ -9,6 +9,7 @@ import 'package:eatvio_app/features/glossary/models/glossary_model.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import '../../../fixtures/fixture_reader.dart'; import 'diary_repository_test.mocks.dart'; @GenerateNiceMocks([MockSpec()]) @@ -24,23 +25,9 @@ void main() { test('getDiaryIndexByDate - возвращает список дневников по дате', () async { const date = '2024-01-15'; - final expectedDiaryList = [ - const DiaryDayModel( - id: 1, - date: date, - closed: 0, - comment: '', - typeOfDiary: TypeOfDiaryModel( - hasChosenDiet: false, - hasChosenPlan: false, - diaryState: null, - ), - meals: [], - chosenPlanId: null, - dayOfChosenDiet: null, - diet: null, - ), - ]; + final json = FixtureReader.readAsMap('diary/diary_day_response.json'); + final expectedDiary = DiaryDayModel.fromJson(json); + final expectedDiaryList = [expectedDiary]; when(mockDiaryService.getDiaryIndexByDate(date: date)) .thenAnswer((_) async => expectedDiaryList); @@ -92,23 +79,8 @@ void main() { ), ]; - const glossaryItem = GlossaryPaginationModel( - glossariesList: [ - GlossaryModel( - id: 10, - name: 'Яблоко', - grInPortion: 100, - energyOn100Gr: 52.0, - proteinsOn100Gr: 0.3, - fatsOn100Gr: 0.2, - carbohydratesOn100Gr: 14.0, - energyOnPortion: 52.0, - proteinsOnPortion: 0.3, - fatsOnPortion: 0.2, - carbohydratesOnPortion: 14.0, - ), - ], - ); + final glossaryJson = FixtureReader.readAsMap('diary/glossary_pagination_response.json'); + final glossaryItem = GlossaryPaginationModel.fromJson(glossaryJson); when(mockDiaryService.getDiaryIndexByDate(date: date)) .thenAnswer((_) async => diaryList); @@ -214,23 +186,8 @@ void main() { ), ); - const glossaryItem = GlossaryPaginationModel( - glossariesList: [ - GlossaryModel( - id: 10, - name: 'Яблоко', - grInPortion: 100, - energyOn100Gr: 52.0, - proteinsOn100Gr: 0.3, - fatsOn100Gr: 0.2, - carbohydratesOn100Gr: 14.0, - energyOnPortion: 52.0, - proteinsOnPortion: 0.3, - fatsOnPortion: 0.2, - carbohydratesOnPortion: 14.0, - ), - ], - ); + final glossaryJson = FixtureReader.readAsMap('diary/glossary_pagination_response.json'); + final glossaryItem = GlossaryPaginationModel.fromJson(glossaryJson); when(mockDiaryService.getDiaryDay(diary: diaryId)) .thenAnswer((_) async => diaryWrapper); @@ -246,20 +203,8 @@ void main() { test('getNutritionData - возвращает данные о питании', () async { const diaryId = 1; - const expectedNutrition = NutritionDataModel( - dailyNutritionIntake: NutritionModel( - energy: 2000.0, - proteins: 150.0, - fats: 80.0, - carbohydrates: 250.0, - ), - dailyNutritionRecommendation: NutritionModel( - energy: 2200.0, - proteins: 160.0, - fats: 90.0, - carbohydrates: 270.0, - ), - ); + final json = FixtureReader.readAsMap('diary/nutrition_response.json'); + final expectedNutrition = NutritionDataModel.fromJson(json); when(mockDiaryService.getNutrition(diary: diaryId)) .thenAnswer((_) async => expectedNutrition); @@ -835,23 +780,8 @@ void main() { diet: null, ); - const glossaryItem = GlossaryPaginationModel( - glossariesList: [ - GlossaryModel( - id: 10, - name: 'Яблоко', - grInPortion: 100, - energyOn100Gr: 52.0, - proteinsOn100Gr: 0.3, - fatsOn100Gr: 0.2, - carbohydratesOn100Gr: 14.0, - energyOnPortion: 52.0, - proteinsOnPortion: 0.3, - fatsOnPortion: 0.2, - carbohydratesOnPortion: 14.0, - ), - ], - ); + final glossaryJson = FixtureReader.readAsMap('diary/glossary_pagination_response.json'); + final glossaryItem = GlossaryPaginationModel.fromJson(glossaryJson); when(mockDiaryService.getDiaryDayV2(day: day)) .thenAnswer((_) async => diaryDay); diff --git a/test/features/diets/repositories/diet_repository_test.dart b/test/features/diets/repositories/diet_repository_test.dart index b2ab14e6..014c78be 100644 --- a/test/features/diets/repositories/diet_repository_test.dart +++ b/test/features/diets/repositories/diet_repository_test.dart @@ -6,6 +6,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import '../../../fixtures/fixture_reader.dart'; import 'diet_repository_test.mocks.dart'; @GenerateNiceMocks([MockSpec()]) @@ -21,10 +22,8 @@ void main() { test('likeDiet - успешный лайк', () async { const dietId = 1; - const expectedLikes = DietLikesModel( - totalLikes: 10, - isLiked: true, - ); + final json = FixtureReader.readAsMap('diets/diet_likes_response.json'); + final expectedLikes = DietLikesModel.fromJson(json); when(mockService.likeDiet(id: dietId)) .thenAnswer((_) async => expectedLikes); @@ -37,31 +36,8 @@ void main() { test('getDiet - успешное получение диеты по id', () async { const dietId = 1; - const expectedDiet = Diet( - id: dietId, - slug: 'test-diet', - name: 'Test Diet', - image: 'https://example.com/image.jpg', - duration: 7, - state: DietState.active, - type: DietType(veg: true, light: false, carb: false, meat: false), - details: 'Test details', - dailySchedule: {}, - author: Author( - authorSlug: 'author', - authorName: 'Author Name', - authorProfileIcon: 'https://example.com/icon.jpg', - authorIsMe: false, - isEntitySubscribedByMe: null, - authorPlaceInRating: null, - ), - totalLikes: 10, - totalViews: 100, - totalComments: 5, - wasLikedByMe: false, - isFavorite: false, - dailyNutrition: [], - ); + final json = FixtureReader.readAsMap('diets/diet_response.json'); + final expectedDiet = Diet.fromJson(json); when(mockService.getDiet(id: dietId)) .thenAnswer((_) async => expectedDiet); @@ -75,31 +51,8 @@ void main() { test('getDietBySlug - успешное получение диеты по slug', () async { const slug = 'test-diet'; - const expectedDiet = Diet( - id: 1, - slug: slug, - name: 'Test Diet', - image: 'https://example.com/image.jpg', - duration: 7, - state: DietState.active, - type: DietType(veg: true, light: false, carb: false, meat: false), - details: 'Test details', - dailySchedule: {}, - author: Author( - authorSlug: 'author', - authorName: 'Author Name', - authorProfileIcon: 'https://example.com/icon.jpg', - authorIsMe: false, - isEntitySubscribedByMe: null, - authorPlaceInRating: null, - ), - totalLikes: 10, - totalViews: 100, - totalComments: 5, - wasLikedByMe: false, - isFavorite: false, - dailyNutrition: [], - ); + final json = FixtureReader.readAsMap('diets/diet_response.json'); + final expectedDiet = Diet.fromJson(json); when(mockService.getDietBySlug(slug: slug)) .thenAnswer((_) async => expectedDiet); @@ -113,31 +66,10 @@ void main() { test('addToFavorite - успешное добавление в избранное', () async { const dietId = 1; - const expectedDiet = Diet( - id: dietId, - slug: 'test-diet', - name: 'Test Diet', - image: 'https://example.com/image.jpg', - duration: 7, - state: DietState.active, - type: DietType(veg: true, light: false, carb: false, meat: false), - details: 'Test details', - dailySchedule: {}, - author: Author( - authorSlug: 'author', - authorName: 'Author Name', - authorProfileIcon: 'https://example.com/icon.jpg', - authorIsMe: false, - isEntitySubscribedByMe: null, - authorPlaceInRating: null, - ), - totalLikes: 10, - totalViews: 100, - totalComments: 5, - wasLikedByMe: false, - isFavorite: true, - dailyNutrition: [], - ); + final json = FixtureReader.readAsMap('diets/diet_response.json'); + final dietJson = Map.from(json); + dietJson['is_favorite'] = true; + final expectedDiet = Diet.fromJson(dietJson); when(mockService.addToFavorite(id: dietId)) .thenAnswer((_) async => expectedDiet); @@ -151,31 +83,8 @@ void main() { test('removeFromFavorite - успешное удаление из избранного', () async { const dietId = 1; - const expectedDiet = Diet( - id: dietId, - slug: 'test-diet', - name: 'Test Diet', - image: 'https://example.com/image.jpg', - duration: 7, - state: DietState.active, - type: DietType(veg: true, light: false, carb: false, meat: false), - details: 'Test details', - dailySchedule: {}, - author: Author( - authorSlug: 'author', - authorName: 'Author Name', - authorProfileIcon: 'https://example.com/icon.jpg', - authorIsMe: false, - isEntitySubscribedByMe: null, - authorPlaceInRating: null, - ), - totalLikes: 10, - totalViews: 100, - totalComments: 5, - wasLikedByMe: false, - isFavorite: false, - dailyNutrition: [], - ); + final json = FixtureReader.readAsMap('diets/diet_response.json'); + final expectedDiet = Diet.fromJson(json); when(mockService.removeFromFavorite(id: dietId)) .thenAnswer((_) async => expectedDiet); diff --git a/test/features/feed/repositories/feed_repository_test.dart b/test/features/feed/repositories/feed_repository_test.dart index f9f44f8f..d2a56a55 100644 --- a/test/features/feed/repositories/feed_repository_test.dart +++ b/test/features/feed/repositories/feed_repository_test.dart @@ -14,6 +14,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import '../../../fixtures/fixture_reader.dart'; import 'feed_repository_test.mocks.dart'; @GenerateNiceMocks([MockSpec()]) @@ -86,28 +87,8 @@ void main() { test('getBlogPost - успешное получение поста', () async { const postId = 1; - final expectedPost = FeedBlogPostModel( - id: postId, - state: 'published', - image: 'https://example.com/image.jpg', - description: 'Описание', - author: const Author( - authorSlug: 'author-slug', - authorName: 'Автор', - authorProfileIcon: 'https://example.com/photo.jpg', - authorIsMe: false, - isEntitySubscribedByMe: null, - authorPlaceInRating: null, - ), - videoUrl: '', - createdAt: DateTime.now(), - updatedAt: DateTime.now(), - title: 'Заголовок', - totalLikes: 10, - totalViews: 100, - totalComments: 5, - wasLikedByMe: false, - ); + final json = FixtureReader.readAsMap('feed/feed_blog_post_response.json'); + final expectedPost = FeedBlogPostModel.fromJson(json); when(mockFeedService.getBlogPost(postId: postId)).thenAnswer((_) async => expectedPost); @@ -246,36 +227,8 @@ void main() { const duration = 30; const minPrice = 1000; const maxPrice = 5000; - final expectedPlans = PlanPaginationModel( - data: [ - PlanModel( - id: 1, - slug: 'weight-loss-plan', - name: 'Weight Loss Plan', - image: 'https://example.com/plan.jpg', - duration: duration, - state: 'active', - type: const PlanType(fit: false, slim: true, behavior: false, wellness: false), - details: 'Weight loss plan description', - packetsCount: 30, - author: const Author( - authorSlug: 'consultant-1', - authorName: 'Consultant Name', - authorProfileIcon: 'https://example.com/consultant.jpg', - authorIsMe: false, - ), - totalLikes: 100, - totalViews: 1000, - totalComments: 50, - isFavorite: false, - minPriceOfOptions: minPrice.toDouble(), - maxPriceOfOptions: maxPrice.toDouble(), - wasLikedByMe: false, - ), - ], - links: const Links(first: '', last: '', prev: null, next: null), - meta: const Meta(currentPage: 1, lastPage: 1, total: 1, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), - ); + final json = FixtureReader.readAsMap('feed/plan_pagination_response.json'); + final expectedPlans = PlanPaginationModel.fromJson(json); when( mockFeedService.getPlans(page: page, query: query, types: types, duration: duration, minPrice: minPrice, maxPrice: maxPrice), @@ -310,21 +263,8 @@ void main() { test('getBlogPostComments - возвращает комментарии поста блога', () async { const id = '1'; - final expectedComments = CommentModel( - data: [ - Comment( - id: 1, - authorName: 'User 1', - authorSlug: 'user-1', - authorProfileIcon: 'https://example.com/user1.jpg', - body: 'Great post!', - childrenComments: [], - createdAt: DateTime(2024, 1, 15), - ), - ], - links: const Links(first: '', last: '', prev: null, next: null), - meta: const Meta(currentPage: 1, lastPage: 1, total: 1, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), - ); + final json = FixtureReader.readAsMap('feed/comment_response.json'); + final expectedComments = CommentModel.fromJson(json); when(mockFeedService.getBlogPostComments(id: id)).thenAnswer((_) async => expectedComments); @@ -498,22 +438,8 @@ void main() { test('getConsultants - возвращает список консультантов', () async { const name = 'Anna'; - final expectedConsultants = [ - const FeedConsultantModel( - slug: 'consultant-1', - name: 'Anna Ivanova', - description: 'Test consultant description', - totalScores: 5, - photo: 'https://example.com/consultant1.jpg', - badges: [], - ), - ]; - - final expectedPagination = FeedConsultantPaginationModel( - data: expectedConsultants, - links: const Links(first: '', last: '', prev: null, next: null), - meta: const Meta(currentPage: 1, lastPage: 1, total: 1, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), - ); + final json = FixtureReader.readAsMap('feed/consultant_pagination_response.json'); + final expectedPagination = FeedConsultantPaginationModel.fromJson(json); when(mockFeedService.getConsultants(name: name)).thenAnswer((_) async => expectedPagination); diff --git a/test/features/glossary/services/glossary_service_test.dart b/test/features/glossary/services/glossary_service_test.dart new file mode 100644 index 00000000..d3bb1dc3 --- /dev/null +++ b/test/features/glossary/services/glossary_service_test.dart @@ -0,0 +1,35 @@ +import 'package:eatvio_app/features/glossary/models/glossary_model.dart'; +import 'package:eatvio_app/features/glossary/services/glossary_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import '../../../fixtures/fixture_reader.dart'; +import 'glossary_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('GlossaryService', () { + late MockGlossaryService mockGlossaryService; + + setUp(() { + mockGlossaryService = MockGlossaryService(); + }); + + test('getGlossaryByQuery - возвращает глоссарий по запросу', () async { + const query = 'яблоко'; + final json = FixtureReader.readAsMap('diary/glossary_pagination_response.json'); + final expectedGlossary = GlossaryPaginationModel.fromJson(json); + + when(mockGlossaryService.getGlossaryByQuery(query: query)) + .thenAnswer((_) async => expectedGlossary); + + final result = await mockGlossaryService.getGlossaryByQuery(query: query); + + expect(result, isA()); + expect(result.glossariesList.length, 1); + verify(mockGlossaryService.getGlossaryByQuery(query: query)).called(1); + }); + }); +} + diff --git a/test/features/my_diets/repositories/my_diets_repository_test.dart b/test/features/my_diets/repositories/my_diets_repository_test.dart index 51ebcde9..c31bb6aa 100644 --- a/test/features/my_diets/repositories/my_diets_repository_test.dart +++ b/test/features/my_diets/repositories/my_diets_repository_test.dart @@ -6,6 +6,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import '../../../fixtures/fixture_reader.dart'; import 'my_diets_repository_test.mocks.dart'; @GenerateNiceMocks([MockSpec()]) @@ -26,30 +27,8 @@ void main() { const types = 'light,veg'; const duration = 30; const sorting = 'name'; - const expected = DietsPagination( - data: [ - Diet( - id: 1, - slug: 'test-diet', - name: 'Test Diet', - image: 'https://someurl.com/img.jpg', - duration: duration, - state: DietState.active, - type: DietType(light: true, veg: false, carb: false, meat: false), - details: 'Test diet description', - dailySchedule: {}, - author: Author(authorSlug: '', authorName: '', authorProfileIcon: '', authorIsMe: false), - totalLikes: 1, - totalViews: 1, - totalComments: 1, - wasLikedByMe: false, - isFavorite: false, - dailyNutrition: [], - ), - ], - links: Links(first: '', last: '', prev: null, next: null), - meta: Meta(currentPage: 1, lastPage: 1, total: 1, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), - ); + final json = FixtureReader.readAsMap('feed/diets_pagination_response.json'); + final expected = DietsPagination.fromJson(json); when(mockMyDietsService.getDiets( page: page, @@ -71,7 +50,7 @@ void main() { expect(result, isA()); expect(result.data.length, 1); - expect(result.data.first.name, 'Test Diet'); + expect(result.data.first.name, 'Keto Diet'); verify(mockMyDietsService.getDiets( page: page, query: query, @@ -116,30 +95,26 @@ void main() { const page = 2; const query = 'wellness'; const duration = 21; - const expected = DietsPagination( - data: [ - Diet( - id: 2, - slug: 'another-diet', - name: 'Another Diet', - image: 'https://someurl.com/img2.jpg', - duration: duration, - state: DietState.draft, - type: DietType(light: false, veg: true, carb: false, meat: false), - details: '', - dailySchedule: {}, - author: Author(authorSlug: 'author-slug', authorName: 'Author Name', authorProfileIcon: '', authorIsMe: true), - totalLikes: 5, - totalViews: 10, - totalComments: 2, - wasLikedByMe: true, - isFavorite: true, - dailyNutrition: [], - ), - ], - links: Links(first: '', last: '', prev: null, next: null), - meta: Meta(currentPage: 2, lastPage: 2, total: 1, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), - ); + final json = FixtureReader.readAsMap('feed/diets_pagination_response.json'); + final dietJson = Map.from(json); + final dietData = List>.from(dietJson['data'] as List); + dietData.first['id'] = 2; + dietData.first['slug'] = 'another-diet'; + dietData.first['name'] = 'Another Diet'; + dietData.first['image'] = 'https://someurl.com/img2.jpg'; + dietData.first['duration'] = duration; + dietData.first['state'] = 'draft'; + dietData.first['type'] = {'light': false, 'veg': true, 'carb': false, 'meat': false}; + dietData.first['description_md'] = ''; + dietData.first['author'] = {'author_slug': 'author-slug', 'author_name': 'Author Name', 'author_profile_icon': '', 'author_is_me': true, 'is_entity_subscribed_by_me': null, 'author_place_in_rating': null}; + dietData.first['total_likes'] = 5; + dietData.first['total_views'] = 10; + dietData.first['total_comments'] = 2; + dietData.first['was_liked_by_me'] = true; + dietData.first['is_favorite'] = true; + dietJson['data'] = dietData; + dietJson['meta'] = {'current_page': 2, 'from': null, 'last_page': 2, 'links': [{'url': null, 'label': null, 'active': null}], 'per_page': 10, 'to': null, 'total': 1, 'total_min_price': null, 'total_max_price': null}; + final expected = DietsPagination.fromJson(dietJson); when(mockMyDietsService.getDiets( page: page, diff --git a/test/features/my_finance/services/cards_service_test.dart b/test/features/my_finance/services/cards_service_test.dart new file mode 100644 index 00000000..d023c881 --- /dev/null +++ b/test/features/my_finance/services/cards_service_test.dart @@ -0,0 +1,78 @@ +import 'package:eatvio_app/features/my_finance/models/card_model.dart'; +import 'package:eatvio_app/features/my_finance/models/payment_url_model.dart'; +import 'package:eatvio_app/features/my_finance/services/cards_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'cards_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('CardsService', () { + late MockCardsService mockCardsService; + + setUp(() { + mockCardsService = MockCardsService(); + }); + + test('getCards - возвращает список карт', () async { + final expectedCards = []; + + when(mockCardsService.getCards()) + .thenAnswer((_) async => expectedCards); + + final result = await mockCardsService.getCards(); + + expect(result, isA>()); + verify(mockCardsService.getCards()).called(1); + }); + + test('addCard - добавляет карту', () async { + final expectedUrl = PaymentUrlModel(paymentUrl: 'https://example.com/payment'); + + when(mockCardsService.addCard()) + .thenAnswer((_) async => expectedUrl); + + final result = await mockCardsService.addCard(); + + expect(result, isA()); + expect(result.paymentUrl, 'https://example.com/payment'); + verify(mockCardsService.addCard()).called(1); + }); + + test('markAsDefault - помечает карту как основную', () async { + const id = 1; + + when(mockCardsService.markAsDefault(id: id)) + .thenAnswer((_) async => Future.value()); + + await mockCardsService.markAsDefault(id: id); + + verify(mockCardsService.markAsDefault(id: id)).called(1); + }); + + test('deleteCard - удаляет карту', () async { + const id = 1; + + when(mockCardsService.deleteCard(id: id)) + .thenAnswer((_) async => Future.value()); + + await mockCardsService.deleteCard(id: id); + + verify(mockCardsService.deleteCard(id: id)).called(1); + }); + + test('collectCharge - собирает платеж', () async { + const chosenPlanId = 1; + + when(mockCardsService.collectCharge(chosenPlanId: chosenPlanId)) + .thenAnswer((_) async => Future.value()); + + await mockCardsService.collectCharge(chosenPlanId: chosenPlanId); + + verify(mockCardsService.collectCharge(chosenPlanId: chosenPlanId)).called(1); + }); + }); +} + diff --git a/test/features/my_plans/repositories/my_plans_repository_test.dart b/test/features/my_plans/repositories/my_plans_repository_test.dart index 9b15f251..5999b9c0 100644 --- a/test/features/my_plans/repositories/my_plans_repository_test.dart +++ b/test/features/my_plans/repositories/my_plans_repository_test.dart @@ -7,6 +7,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import '../../../fixtures/fixture_reader.dart'; import 'my_plans_repository_test.mocks.dart'; @GenerateNiceMocks([MockSpec()]) @@ -27,31 +28,8 @@ void main() { const duration = 30; const minPrice = 100; const maxPrice = 500; - final expected = PlanPaginationModel( - data: [ - PlanModel( - id: 1, - slug: 'test-plan', - name: 'Test Plan', - image: 'https://someurl.com/img.jpg', - duration: duration, - state: 'active', - type: const PlanType(fit: true, slim: false, behavior: false, wellness: false), - details: 'Test plan description', - packetsCount: 1, - author: const Author(authorSlug: '', authorName: '', authorProfileIcon: '', authorIsMe: false), - totalLikes: 1, - totalViews: 1, - totalComments: 1, - isFavorite: false, - minPriceOfOptions: minPrice.toDouble(), - maxPriceOfOptions: maxPrice.toDouble(), - wasLikedByMe: false, - ), - ], - links: const Links(first: '', last: '', prev: null, next: null), - meta: const Meta(currentPage: 1, lastPage: 1, total: 1, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), - ); + final json = FixtureReader.readAsMap('feed/plan_pagination_response.json'); + final expected = PlanPaginationModel.fromJson(json); when(mockMyPlansService.getPlans( page: page, @@ -73,7 +51,7 @@ void main() { expect(result, isA()); expect(result.data.length, 1); - expect(result.data.first.name, 'Test Plan'); + expect(result.data.first.name, 'Weight Loss Plan'); verify(mockMyPlansService.getPlans( page: page, query: query, diff --git a/test/features/notifications/service/notifications_service_test.dart b/test/features/notifications/service/notifications_service_test.dart index 96203ba6..388a16c1 100644 --- a/test/features/notifications/service/notifications_service_test.dart +++ b/test/features/notifications/service/notifications_service_test.dart @@ -1,173 +1,62 @@ import 'package:dio/dio.dart'; -import 'package:eatvio_app/features/notifications/models/notification_model.dart'; import 'package:eatvio_app/features/notifications/service/notifications_service.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import '../../../fixtures/fixture_reader.dart'; import 'notifications_service_test.mocks.dart'; -@GenerateMocks([Dio]) +@GenerateNiceMocks([MockSpec()]) void main() { group('NotificationsService', () { - late NotificationsService service; + late NotificationsService notificationsService; late MockDio mockDio; setUp(() { mockDio = MockDio(); - service = NotificationsService(mockDio); + notificationsService = NotificationsService(mockDio); }); - test('getNotifications returns null when status code is not 200', () async { - when(mockDio.get(any)).thenAnswer((_) async => Response( - requestOptions: RequestOptions(path: '/api/profile/notifications'), - statusCode: 404, - data: {}, - )); - - final result = await service.getNotifications(page: 1); - - expect(result, isNull); - }); - - test('getNotifications parses notifications correctly', () async { - when(mockDio.get(any)).thenAnswer((_) async => Response( - requestOptions: RequestOptions(path: '/api/profile/notifications'), - statusCode: 200, - data: { - 'data': [ - { - 'type': 'diary-reminder-notification', - 'read_at': null, - 'created_at': '2024-01-15T10:30:00Z', - 'data': {}, - } - ], - 'current_page': 1, - 'last_page': 1, - 'per_page': 10, - 'total': 1, - }, - )); - - final result = await service.getNotifications(page: 1); - - expect(result, isNotNull); - expect(result!['notifications'], isA()); - expect(result['pagination'], isA()); - expect(result['pagination']['current_page'], 1); - }); - - test('getNotifications handles unknown notification type', () async { - when(mockDio.get(any)).thenAnswer((_) async => Response( - requestOptions: RequestOptions(path: '/api/profile/notifications'), - statusCode: 200, - data: { - 'data': [ - { - 'type': 'unknown-type', - 'read_at': null, - 'created_at': '2024-01-15T10:30:00Z', - 'data': {}, - } - ], - 'current_page': 1, - 'last_page': 1, - 'per_page': 10, - 'total': 1, - }, - )); - - final result = await service.getNotifications(page: 1); - - expect(result, isNotNull); - expect(result!['notifications'], isA()); - final notifications = result['notifications'] as List; - expect(notifications.first, isA()); - }); - - test('getNotifications handles notification_class_name field', () async { - when(mockDio.get(any)).thenAnswer((_) async => Response( - requestOptions: RequestOptions(path: '/api/profile/notifications'), - statusCode: 200, - data: { - 'data': [ - { - 'notification_class_name': 'App\\Notifications\\DiaryReminderNotification', - 'read_at': null, - 'created_at': '2024-01-15T10:30:00Z', - 'data': {}, - } - ], - 'current_page': 1, - 'last_page': 1, - 'per_page': 10, - 'total': 1, - }, - )); - - final result = await service.getNotifications(page: 1); - - expect(result, isNotNull); - expect(result!['notifications'], isA()); - }); - - test('getNotifications handles read_at correctly', () async { - when(mockDio.get(any)).thenAnswer((_) async => Response( - requestOptions: RequestOptions(path: '/api/profile/notifications'), - statusCode: 200, - data: { - 'data': [ - { - 'type': 'diary-reminder-notification', - 'read_at': '2024-01-15T10:30:00Z', - 'created_at': '2024-01-15T10:30:00Z', - 'data': {}, - } - ], - 'current_page': 1, - 'last_page': 1, - 'per_page': 10, - 'total': 1, - }, - )); - - final result = await service.getNotifications(page: 1); - - expect(result, isNotNull); - expect(result!['notifications'], isA()); - }); - - test('getNotifications rethrows exceptions', () async { - when(mockDio.get(any)).thenThrow(DioException( + test('getNotifications - возвращает уведомления', () async { + const page = 1; + final json = FixtureReader.readAsMap('notifications/notifications_response.json'); + final response = Response( + data: { + 'data': json['notifications'], + 'current_page': json['pagination']['current_page'], + 'last_page': json['pagination']['last_page'], + 'per_page': 10, + 'total': 1, + }, + statusCode: 200, requestOptions: RequestOptions(path: '/api/profile/notifications'), - )); + ); - expect(() => service.getNotifications(page: 1), throwsA(isA())); + when(mockDio.get(any)) + .thenAnswer((_) async => response); + + final result = await notificationsService.getNotifications(page: page); + + expect(result, isA?>()); + expect(result, isNotNull); + expect(result!['notifications'], isA()); + verify(mockDio.get(any)).called(1); }); - test('markNotificationsAsRead calls correct endpoint', () async { - when(mockDio.post(any)).thenAnswer((_) async => Response( - requestOptions: RequestOptions(path: '/api/profile/mark_notifications_as_readed'), - statusCode: 200, - )); - - await service.markNotificationsAsRead(); - - verify(mockDio.post('/api/profile/mark_notifications_as_readed')).called(1); - }); - - test('markNotificationsAsRead rethrows exceptions', () async { - when(mockDio.post(any)).thenThrow(DioException( + test('markNotificationsAsRead - помечает уведомления как прочитанные', () async { + final response = Response( + data: {}, + statusCode: 200, requestOptions: RequestOptions(path: '/api/profile/mark_notifications_as_readed'), - )); + ); - expect(() => service.markNotificationsAsRead(), throwsA(isA())); + when(mockDio.post(any)) + .thenAnswer((_) async => response); + + await notificationsService.markNotificationsAsRead(); + + verify(mockDio.post(any)).called(1); }); }); } - - - - - diff --git a/test/features/personal_diet_suggestion/services/personal_diet_suggestion_service_test.dart b/test/features/personal_diet_suggestion/services/personal_diet_suggestion_service_test.dart new file mode 100644 index 00000000..907aff3f --- /dev/null +++ b/test/features/personal_diet_suggestion/services/personal_diet_suggestion_service_test.dart @@ -0,0 +1,74 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/features/consultations/models/consultation_model.dart'; +import 'package:eatvio_app/features/personal_diet_suggestion/services/personal_diet_suggestion_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import '../../../fixtures/fixture_reader.dart'; +import 'personal_diet_suggestion_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('PersonalDietSuggestionService', () { + late PersonalDietSuggestionService personalDietSuggestionService; + late MockDio mockDio; + + setUp(() { + mockDio = MockDio(); + personalDietSuggestionService = PersonalDietSuggestionService(mockDio); + }); + + test('getConsultationWithPersonalDiets - возвращает консультации с персональными диетами', () async { + final json = FixtureReader.readAsMap('consultations/consultation_pagination_response.json'); + final response = Response( + data: json, + statusCode: 200, + requestOptions: RequestOptions(path: '/api/consultations'), + ); + + when(mockDio.get(any, queryParameters: anyNamed('queryParameters'))) + .thenAnswer((_) async => response); + + final result = await personalDietSuggestionService.getConsultationWithPersonalDiets(); + + expect(result, isA()); + verify(mockDio.get(any, queryParameters: anyNamed('queryParameters'))).called(1); + }); + + test('attachPersonalDiet - прикрепляет персональную диету', () async { + const consultationId = 1; + const dietId = 2; + final response = Response( + data: {}, + statusCode: 200, + requestOptions: RequestOptions(path: '/api/chosen_plans/$consultationId/attach_diet'), + ); + + when(mockDio.post(any, data: anyNamed('data'))) + .thenAnswer((_) async => response); + + await personalDietSuggestionService.attachPersonalDiet(consultationId: consultationId, dietId: dietId); + + verify(mockDio.post(any, data: anyNamed('data'))).called(1); + }); + + test('reattachPersonalDiet - переприкрепляет персональную диету', () async { + const consultationId = 1; + const dietId = 2; + final response = Response( + data: {}, + statusCode: 200, + requestOptions: RequestOptions(path: '/api/chosen_plans/$consultationId/re_attach_diet'), + ); + + when(mockDio.post(any, data: anyNamed('data'))) + .thenAnswer((_) async => response); + + await personalDietSuggestionService.reattachPersonalDiet(consultationId: consultationId, dietId: dietId); + + verify(mockDio.post(any, data: anyNamed('data'))).called(1); + }); + }); +} + diff --git a/test/features/plans/repositories/plans_repository_test.dart b/test/features/plans/repositories/plans_repository_test.dart index cb485342..7992cae0 100644 --- a/test/features/plans/repositories/plans_repository_test.dart +++ b/test/features/plans/repositories/plans_repository_test.dart @@ -1,5 +1,3 @@ -import 'package:eatvio_app/core/models/pagination_model.dart'; -import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; import 'package:eatvio_app/features/plans/repositories/plans_repository.dart'; import 'package:eatvio_app/features/plans/services/plans_service.dart'; @@ -7,6 +5,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import '../../../fixtures/fixture_reader.dart'; import 'plans_repository_test.mocks.dart'; @GenerateNiceMocks([MockSpec()]) @@ -22,45 +21,15 @@ void main() { test('getPlansBySlug - успешное получение планов', () async { const slug = 'test-author'; - const plan = PlanModel( - id: 1, - slug: 'test-plan', - name: 'Test Plan', - image: 'https://example.com/image.jpg', - duration: 7, - state: 'active', - type: PlanType(fit: true, slim: false, behavior: false, wellness: false), - details: 'Test details', - packetsCount: 3, - author: Author( - authorSlug: 'test-author', - authorName: 'Author Name', - authorProfileIcon: 'https://example.com/icon.jpg', - authorIsMe: false, - isEntitySubscribedByMe: null, - authorPlaceInRating: null, - ), - totalLikes: 10, - totalViews: 100, - totalComments: 5, - isFavorite: false, - minPriceOfOptions: 1000.0, - maxPriceOfOptions: 2000.0, - wasLikedByMe: false, - ); - - const pagination = PlanPaginationModel( - data: [plan], - links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=1', prev: null, next: null), - meta: Meta(currentPage: 1, from: 1, lastPage: 1, links: [], perPage: 10, to: 1, total: 1), - ); + final paginationJson = FixtureReader.readAsMap('feed/plan_pagination_response.json'); + final pagination = PlanPaginationModel.fromJson(paginationJson); when(mockService.getPlansBySlug(author: slug)).thenAnswer((_) async => pagination); final result = await repository.getPlansBySlug(slug); expect(result.length, 1); - expect(result.first.slug, 'test-plan'); + expect(result.first.slug, 'weight-loss-plan'); verify(mockService.getPlansBySlug(author: slug)).called(1); }); }); diff --git a/test/features/recipes/repositories/my_recipes_repository_test.dart b/test/features/recipes/repositories/my_recipes_repository_test.dart index 670b90b8..e0a8b994 100644 --- a/test/features/recipes/repositories/my_recipes_repository_test.dart +++ b/test/features/recipes/repositories/my_recipes_repository_test.dart @@ -1,4 +1,3 @@ -import 'package:eatvio_app/features/feed/models/recipes_model.dart'; import 'package:eatvio_app/features/recipe/models/my_recipe_model.dart'; import 'package:eatvio_app/features/recipe/repositories/my_recipes_repository.dart'; import 'package:eatvio_app/features/recipe/services/my_recipes_service.dart'; @@ -6,6 +5,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import '../../../fixtures/fixture_reader.dart'; import 'my_recipes_repository_test.mocks.dart'; @GenerateNiceMocks([MockSpec()]) @@ -18,29 +18,11 @@ void main() { mockMyRecipesService = MockMyRecipesService(); myRecipesRepository = MyRecipesRepository(myRecipesService: mockMyRecipesService); }); - +// cancel_bottom_sheet +// dev_tools test('getMyRecipes returns list of recipes', () async { - const expectedPagination = MyRecipePaginationModel( - data: [ - MyRecipeModel( - id: 1, - image: 'https://someurl.com/img.jpg', - state: 'published', - cookingTime: 30, - activeCookingTime: 20, - description: 'Test recipe description', - steps: [ - Step(image: 'https://someurl.com/step1.jpg', description: 'Step 1 description'), - ], - videoUrl: 'https://someurl.com/video.mp4', - title: 'Test Recipe', - slug: 'test-recipe', - calories: 250.0, - likesCount: 5, - viewsCount: 10, - ), - ], - ); + final json = FixtureReader.readAsMap('recipes/my_recipe_pagination_response.json'); + final expectedPagination = MyRecipePaginationModel.fromJson(json); when(mockMyRecipesService.getMyRecipes()).thenAnswer((_) async => expectedPagination); @@ -68,42 +50,26 @@ void main() { }); test('getMyRecipes returns multiple recipes', () async { - const expectedPagination = MyRecipePaginationModel( - data: [ - MyRecipeModel( - id: 1, - image: 'https://someurl.com/img1.jpg', - state: 'published', - cookingTime: 30, - activeCookingTime: 20, - description: 'First recipe', - steps: null, - videoUrl: null, - title: 'First Recipe', - slug: 'first-recipe', - calories: 250.0, - likesCount: 5, - viewsCount: 10, - ), - MyRecipeModel( - id: 2, - image: 'https://someurl.com/img2.jpg', - state: 'draft', - cookingTime: 45, - activeCookingTime: 30, - description: 'Second recipe', - steps: [ - Step(image: 'https://someurl.com/step1.jpg', description: 'Step 1'), - ], - videoUrl: 'https://someurl.com/video.mp4', - title: 'Second Recipe', - slug: 'second-recipe', - calories: 350.0, - likesCount: 8, - viewsCount: 15, - ), - ], - ); + final json = FixtureReader.readAsMap('recipes/my_recipe_pagination_response.json'); + final paginationData = List>.from(json['data'] as List); + final secondRecipe = { + 'id': 2, + 'image': 'https://someurl.com/img2.jpg', + 'state': 'draft', + 'cooking_time': 45, + 'active_time': 30, + 'description_md': 'Second recipe', + 'steps': [{'image': 'https://someurl.com/step1.jpg', 'description_md': 'Step 1'}], + 'video_url': 'https://someurl.com/video.mp4', + 'title': 'Second Recipe', + 'slug': 'second-recipe', + 'energy_per_serving': 350.0, + 'total_likes': 8, + 'total_views': 15, + }; + paginationData.add(secondRecipe); + final multiJson = {'data': paginationData}; + final expectedPagination = MyRecipePaginationModel.fromJson(multiJson); when(mockMyRecipesService.getMyRecipes()).thenAnswer((_) async => expectedPagination); @@ -111,7 +77,7 @@ void main() { expect(result, isA>()); expect(result.length, 2); - expect(result.first.title, 'First Recipe'); + expect(result.first.title, 'Test Recipe'); expect(result.last.title, 'Second Recipe'); verify(mockMyRecipesService.getMyRecipes()).called(1); }); diff --git a/test/features/registration/services/registration_service_test.dart b/test/features/registration/services/registration_service_test.dart new file mode 100644 index 00000000..23f19341 --- /dev/null +++ b/test/features/registration/services/registration_service_test.dart @@ -0,0 +1,60 @@ +import 'package:eatvio_app/features/registration/models/location_model.dart'; +import 'package:eatvio_app/features/registration/services/registration_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import '../../../fixtures/fixture_reader.dart'; +import 'registration_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('RegistrationService', () { + late MockRegistrationService mockRegistrationService; + + setUp(() { + mockRegistrationService = MockRegistrationService(); + }); + + test('register - регистрирует нового пользователя', () async { + final expectedResponse = {'success': 'true', 'message': 'User registered'}; + final registrationData = {'first_name': 'John', 'last_name': 'Doe', 'email': 'john@example.com', 'password': 'password123'}; + + when(mockRegistrationService.register(sheet: registrationData)).thenAnswer((_) async => expectedResponse); + + final result = await mockRegistrationService.register(sheet: registrationData); + + expect(result, isA>()); + verify(mockRegistrationService.register(sheet: registrationData)).called(1); + }); + + test('getLocationsByAddress - возвращает локации по адресу', () async { + const query = 'Москва'; + final locationJson = FixtureReader.readAsMap('registration/location_response.json'); + final expectedLocation = LocationModel.fromJson(locationJson); + + when(mockRegistrationService.getLocationsByAddress(query: query)).thenAnswer((_) async => expectedLocation); + + final result = await mockRegistrationService.getLocationsByAddress(query: query); + + expect(result, isA()); + expect(result.locations.length, 2); + verify(mockRegistrationService.getLocationsByAddress(query: query)).called(1); + }); + + test('getLocationsByCoordinate - возвращает локации по координатам', () async { + const latitude = '55.7558'; + const longitude = '37.6173'; + final locationJson = FixtureReader.readAsMap('registration/location_response.json'); + final expectedLocation = LocationModel.fromJson(locationJson); + + when(mockRegistrationService.getLocationsByCoordinate(latitude: latitude, longitude: longitude)).thenAnswer((_) async => expectedLocation); + + final result = await mockRegistrationService.getLocationsByCoordinate(latitude: latitude, longitude: longitude); + + expect(result, isA()); + expect(result.locations.length, 2); + verify(mockRegistrationService.getLocationsByCoordinate(latitude: latitude, longitude: longitude)).called(1); + }); + }); +} diff --git a/test/fixtures/calendar/calendar_response.json b/test/fixtures/calendar/calendar_response.json new file mode 100644 index 00000000..499e6ef7 --- /dev/null +++ b/test/fixtures/calendar/calendar_response.json @@ -0,0 +1,13 @@ +[ + { + "date": "2024-01-15", + "is_current_day_included_in_the_chosen_diet_progression": true, + "diary": null + }, + { + "date": "2024-01-16", + "is_current_day_included_in_the_chosen_diet_progression": false, + "diary": null + } +] + diff --git a/test/fixtures/chat/chat_message_response.json b/test/fixtures/chat/chat_message_response.json new file mode 100644 index 00000000..aafb0147 --- /dev/null +++ b/test/fixtures/chat/chat_message_response.json @@ -0,0 +1,11 @@ +{ + "id": 1, + "data": "Test message", + "media_data": null, + "author_id": 1, + "updated_at": "2024-01-01T12:00:00Z", + "read_by_to_user": false, + "is_author_message_auth_user": true, + "room_id": "chat-1" +} + diff --git a/test/fixtures/chat/chat_message_with_media_response.json b/test/fixtures/chat/chat_message_with_media_response.json new file mode 100644 index 00000000..680a4e9a --- /dev/null +++ b/test/fixtures/chat/chat_message_with_media_response.json @@ -0,0 +1,16 @@ +{ + "id": 2, + "data": "Message with attachment", + "media_data": [ + { + "type": "image", + "url": "https://example.com/image.jpg" + } + ], + "author_id": 1, + "updated_at": "2024-01-01T12:05:00Z", + "read_by_to_user": false, + "is_author_message_auth_user": false, + "room_id": "chat-1" +} + diff --git a/test/fixtures/chat/chat_messages_response.json b/test/fixtures/chat/chat_messages_response.json new file mode 100644 index 00000000..1b5241f5 --- /dev/null +++ b/test/fixtures/chat/chat_messages_response.json @@ -0,0 +1,28 @@ +{ + "data": [ + { + "id": 1, + "data": "First message", + "media_data": null, + "author_id": 1, + "updated_at": "2024-01-01T12:00:00Z", + "read_by_to_user": false, + "is_author_message_auth_user": true, + "room_id": "chat-1" + }, + { + "id": 2, + "data": "Second message", + "media_data": null, + "author_id": 2, + "updated_at": "2024-01-01T12:05:00Z", + "read_by_to_user": true, + "is_author_message_auth_user": false, + "room_id": "chat-1" + } + ], + "meta": { + "last_page": 1 + } +} + diff --git a/test/fixtures/chat/chat_room_pagination_response.json b/test/fixtures/chat/chat_room_pagination_response.json new file mode 100644 index 00000000..e0a3668c --- /dev/null +++ b/test/fixtures/chat/chat_room_pagination_response.json @@ -0,0 +1,64 @@ +{ + "data": [ + { + "id": "chat-1", + "last_message": { + "id": 1, + "data": "Last message", + "media_data": null, + "author_id": 1, + "updated_at": "2024-01-01T12:00:00Z", + "read_by_to_user": false, + "is_author_message_auth_user": true, + "room_id": "chat-1" + }, + "users": { + "from_chat_user": { + "id": 1, + "name": "User 1", + "profile_photo_path": null, + "profile_photo_url": "https://example.com/user1.jpg" + }, + "to_chat_user": { + "id": 2, + "name": "User 2", + "profile_photo_path": null, + "profile_photo_url": "https://example.com/user2.jpg" + } + }, + "unread_messages_count": 5, + "chosen_plan": null + }, + { + "id": "chat-2", + "last_message": null, + "users": { + "from_chat_user": { + "id": 1, + "name": "User 1", + "profile_photo_path": null, + "profile_photo_url": "https://example.com/user1.jpg" + }, + "to_chat_user": { + "id": 3, + "name": "User 3", + "profile_photo_path": null, + "profile_photo_url": "https://example.com/user3.jpg" + } + }, + "unread_messages_count": 0, + "chosen_plan": null + } + ], + "number_of_unread_chat_rooms": 1, + "meta": { + "current_page": 1, + "from": 1, + "last_page": 1, + "links": [], + "per_page": 10, + "to": 2, + "total": 2 + } +} + diff --git a/test/fixtures/chat/chat_room_response.json b/test/fixtures/chat/chat_room_response.json new file mode 100644 index 00000000..f2be32be --- /dev/null +++ b/test/fixtures/chat/chat_room_response.json @@ -0,0 +1,23 @@ +{ + "id": "chat-1", + "chat_room_setting": { + "room_name": "Test Chat Room", + "state": "active" + }, + "users": { + "from_chat_user": { + "id": 1, + "name": "User 1", + "slug": "user-1", + "profile_photo_url": "https://example.com/user1.jpg" + }, + "to_chat_user": { + "id": 2, + "name": "User 2", + "slug": "user-2", + "profile_photo_url": "https://example.com/user2.jpg" + } + }, + "chosen_plan_id": null +} + diff --git a/test/fixtures/chat/chat_room_settings_response.json b/test/fixtures/chat/chat_room_settings_response.json new file mode 100644 index 00000000..94816519 --- /dev/null +++ b/test/fixtures/chat/chat_room_settings_response.json @@ -0,0 +1,5 @@ +{ + "name": "Test Chat Room", + "state": "active" +} + diff --git a/test/fixtures/chat/chat_room_with_plan_response.json b/test/fixtures/chat/chat_room_with_plan_response.json new file mode 100644 index 00000000..484b89d5 --- /dev/null +++ b/test/fixtures/chat/chat_room_with_plan_response.json @@ -0,0 +1,69 @@ +{ + "id": "chat-1", + "chat_room_setting": { + "room_name": "Test Chat Room", + "state": "active" + }, + "users": { + "from_chat_user": { + "id": 1, + "name": "User 1", + "slug": "user-1", + "profile_photo_url": "https://example.com/user1.jpg" + }, + "to_chat_user": { + "id": 2, + "name": "User 2", + "slug": "user-2", + "profile_photo_url": "https://example.com/user2.jpg" + } + }, + "chosen_plan_id": 1, + "chosen_plan": { + "id": 1, + "option_type": "1", + "start_date": "2024-01-01T00:00:00Z", + "last_state": "active", + "chat_id": "chat-1", + "consultant_id": 1, + "plan": { + "id": 1, + "slug": "test-plan", + "name": "Test Plan", + "image": "https://example.com/plan.jpg", + "duration": 30, + "state": "active", + "type": { + "fit": true, + "slim": false, + "behavior": false, + "wellness": false + }, + "description_md": "Plan description", + "packets_count": 1, + "packet1_options": { + "items": ["Item 1", "Item 2"], + "price": 1500.0, + "short": "Option 1", + "description": "Description", + "has_personal_diet": false + }, + "packet2_options": null, + "packet3_options": null, + "author": { + "author_slug": "author-1", + "author_name": "Author Name", + "author_profile_icon": "https://example.com/author.jpg", + "author_is_me": false + }, + "total_likes": 10, + "total_views": 100, + "total_comments": 5, + "is_favorite": false, + "min_price_of_options": 1000.0, + "max_price_of_options": 2000.0, + "was_liked_by_me": false + } + } +} + diff --git a/test/fixtures/chat/chat_user_response.json b/test/fixtures/chat/chat_user_response.json new file mode 100644 index 00000000..1cbf6de3 --- /dev/null +++ b/test/fixtures/chat/chat_user_response.json @@ -0,0 +1,7 @@ +{ + "id": 1, + "name": "Test User", + "slug": "test-user", + "profile_photo_url": "https://example.com/avatar.jpg" +} + diff --git a/test/fixtures/chat/chosen_plan_response.json b/test/fixtures/chat/chosen_plan_response.json new file mode 100644 index 00000000..aa8730e7 --- /dev/null +++ b/test/fixtures/chat/chosen_plan_response.json @@ -0,0 +1,47 @@ +{ + "id": 1, + "option_type": "1", + "start_date": "2024-01-01T00:00:00Z", + "last_state": "in_coordination", + "chat_id": "chat-1", + "consultant_id": 1, + "plan": { + "id": 1, + "slug": "test-plan", + "name": "Test Plan", + "image": "https://example.com/plan.jpg", + "duration": 30, + "state": "active", + "type": { + "fit": true, + "slim": false, + "behavior": false, + "wellness": false + }, + "description_md": "Plan description", + "packets_count": 1, + "packet1_options": { + "items": ["Item 1", "Item 2"], + "price": 1500.0, + "short": "Option 1", + "description_md": "Description", + "has_personal_diet": false + }, + "packet2_options": null, + "packet3_options": null, + "author": { + "author_slug": "author-1", + "author_name": "Author Name", + "author_profile_icon": "https://example.com/author.jpg", + "author_is_me": false + }, + "total_likes": 10, + "total_views": 100, + "total_comments": 5, + "is_favorite": false, + "min_price_of_options": 1000.0, + "max_price_of_options": 2000.0, + "was_liked_by_me": false + } +} + diff --git a/test/fixtures/chat/payment_response.json b/test/fixtures/chat/payment_response.json new file mode 100644 index 00000000..7939cb23 --- /dev/null +++ b/test/fixtures/chat/payment_response.json @@ -0,0 +1,4 @@ +{ + "checkout_url": "https://example.com/checkout/payment-123" +} + diff --git a/test/fixtures/chat/plan_complain_response.json b/test/fixtures/chat/plan_complain_response.json new file mode 100644 index 00000000..b228143a --- /dev/null +++ b/test/fixtures/chat/plan_complain_response.json @@ -0,0 +1,4 @@ +{ + "description": "Test complaint description" +} + diff --git a/test/fixtures/chat/websocket_info_response.json b/test/fixtures/chat/websocket_info_response.json new file mode 100644 index 00000000..9ce23d5d --- /dev/null +++ b/test/fixtures/chat/websocket_info_response.json @@ -0,0 +1,8 @@ +{ + "key": "test-key-123", + "host": "test-host.example.com", + "port": "443", + "cluster": "eu", + "user_id": 1 +} + diff --git a/test/fixtures/consultations/consultation_pagination_response.json b/test/fixtures/consultations/consultation_pagination_response.json new file mode 100644 index 00000000..21fad08d --- /dev/null +++ b/test/fixtures/consultations/consultation_pagination_response.json @@ -0,0 +1,33 @@ +{ + "data": [ + { + "id": 1, + "last_state": "in_progress", + "plan_title": "Weight Loss Plan", + "user_name": "John Doe", + "user_slug": "john-doe", + "consultant_payment": 100.0, + "duration": 30, + "current_diary_day": 5, + "user_profile_photo_url": "photo.jpg", + "consultation_option_price": 50, + "start_date": "2023-01-01", + "end_date": "2023-01-31", + "consultant_id": 10, + "diaries": [ + { + "id": 1, + "state": "started", + "date": "2023-01-01" + }, + { + "id": 2, + "state": "finished", + "date": "2023-01-02" + } + ], + "personal_diet_id": 5 + } + ] +} + diff --git a/test/fixtures/consultations/statistic_response.json b/test/fixtures/consultations/statistic_response.json new file mode 100644 index 00000000..5f203897 --- /dev/null +++ b/test/fixtures/consultations/statistic_response.json @@ -0,0 +1,7 @@ +{ + "total": 10, + "in_progress": 5, + "finished": 3, + "canceled": 2 +} + diff --git a/test/fixtures/diary/diary_day_response.json b/test/fixtures/diary/diary_day_response.json new file mode 100644 index 00000000..a2776bfd --- /dev/null +++ b/test/fixtures/diary/diary_day_response.json @@ -0,0 +1,38 @@ +{ + "id": 1, + "date": "2024-01-15", + "wakeup": "07:00", + "retire": "23:00", + "closed": 0, + "comment": "", + "state": { + "has_chosen_diet": false, + "has_chosen_plan": false, + "diary_state": null + }, + "meals": [ + { + "id": 1, + "time": "12:00", + "type_no": 1, + "satiety": 0, + "mood": 0, + "portions": [ + { + "id": 1, + "product_nutritional_value_id": 10, + "product_name": "Яблоко", + "quantity": 2, + "portion": "100г", + "from_diet": false, + "state": "eaten" + } + ], + "photos": [] + } + ], + "chosen_plan_id": null, + "day_of_chosen_diet": null, + "chosen_diet": null +} + diff --git a/test/fixtures/diary/diary_day_wrapper_response.json b/test/fixtures/diary/diary_day_wrapper_response.json new file mode 100644 index 00000000..178a6d9c --- /dev/null +++ b/test/fixtures/diary/diary_day_wrapper_response.json @@ -0,0 +1,40 @@ +{ + "diary": { + "id": 1, + "date": "2024-01-15", + "wakeup": "07:00", + "retire": "23:00", + "closed": 0, + "comment": "", + "state": { + "has_chosen_diet": false, + "has_chosen_plan": false, + "diary_state": null + }, + "meals": [ + { + "id": 1, + "time": "12:00", + "type_no": 1, + "satiety": 0, + "mood": 0, + "portions": [ + { + "id": 1, + "product_nutritional_value_id": 10, + "product_name": "Яблоко", + "quantity": 2, + "portion": "100г", + "from_diet": false, + "state": "eaten" + } + ], + "photos": [] + } + ], + "chosen_plan_id": null, + "day_of_chosen_diet": null, + "chosen_diet": null + } +} + diff --git a/test/fixtures/diary/glossary_pagination_response.json b/test/fixtures/diary/glossary_pagination_response.json new file mode 100644 index 00000000..4124b282 --- /dev/null +++ b/test/fixtures/diary/glossary_pagination_response.json @@ -0,0 +1,18 @@ +{ + "data": [ + { + "id": 10, + "name": "Яблоко", + "portion_mass_gr": 100, + "energy_on_100gr": 52.0, + "proteins_on_100gr": 0.3, + "fats_on_100gr": 0.2, + "carbohydrates_on_100gr": 14.0, + "energy_on_portion": 52.0, + "proteins_on_portion": 0.3, + "fats_on_portion": 0.2, + "carbohydrates_on_portion": 14.0 + } + ] +} + diff --git a/test/fixtures/diary/nutrition_response.json b/test/fixtures/diary/nutrition_response.json new file mode 100644 index 00000000..ac2b4619 --- /dev/null +++ b/test/fixtures/diary/nutrition_response.json @@ -0,0 +1,15 @@ +{ + "dailyNutritionIntake": { + "energy": 2000.0, + "proteins": 150.0, + "fats": 80.0, + "carbohydrates": 250.0 + }, + "dailyNutritionRecommendation": { + "energy": 2200.0, + "proteins": 160.0, + "fats": 90.0, + "carbohydrates": 270.0 + } +} + diff --git a/test/fixtures/diets/diet_likes_response.json b/test/fixtures/diets/diet_likes_response.json new file mode 100644 index 00000000..e8ee4da9 --- /dev/null +++ b/test/fixtures/diets/diet_likes_response.json @@ -0,0 +1,5 @@ +{ + "total_likers": 10, + "is_liked": true +} + diff --git a/test/fixtures/diets/diet_response.json b/test/fixtures/diets/diet_response.json new file mode 100644 index 00000000..d4d770a9 --- /dev/null +++ b/test/fixtures/diets/diet_response.json @@ -0,0 +1,31 @@ +{ + "id": 1, + "slug": "test-diet", + "name": "Test Diet", + "image": "https://example.com/image.jpg", + "duration": 7, + "state": "active", + "type": { + "veg": true, + "light": false, + "carb": false, + "meat": false + }, + "description_md": "Test details", + "daily_schedule": {}, + "author": { + "author_slug": "author", + "author_name": "Author Name", + "author_profile_icon": "https://example.com/icon.jpg", + "author_is_me": false, + "is_entity_subscribed_by_me": null, + "author_place_in_rating": null + }, + "total_likes": 10, + "total_views": 100, + "total_comments": 5, + "was_liked_by_me": false, + "is_favorite": false, + "daily_nutrition": [] +} + diff --git a/test/fixtures/feed/comment_response.json b/test/fixtures/feed/comment_response.json new file mode 100644 index 00000000..4990b305 --- /dev/null +++ b/test/fixtures/feed/comment_response.json @@ -0,0 +1,32 @@ +{ + "data": [ + { + "id": 1, + "author_name": "User 1", + "author_slug": "user-1", + "author_profile_icon": "https://example.com/user1.jpg", + "body": "Great post!", + "children_comments": [], + "created_at": "2024-01-15T12:00:00Z" + } + ], + "links": { + "first": "http://localhost/api/comments?page=1", + "last": "http://localhost/api/comments?page=1", + "prev": null, + "next": null + }, + "meta": { + "current_page": 1, + "from": 1, + "last_page": 1, + "links": [], + "path": "http://localhost/api/comments", + "per_page": 10, + "to": 1, + "total": 1, + "total_min_price": null, + "total_max_price": null + } +} + diff --git a/test/fixtures/feed/consultant_pagination_response.json b/test/fixtures/feed/consultant_pagination_response.json new file mode 100644 index 00000000..86ebb99e --- /dev/null +++ b/test/fixtures/feed/consultant_pagination_response.json @@ -0,0 +1,32 @@ +{ + "data": [ + { + "slug": "consultant-1", + "name": "Anna Ivanova", + "additional_info": "Test consultant description", + "rating_place": 1, + "total_scores": 5, + "profile_photo_url": "https://example.com/consultant1.jpg", + "badges": [] + } + ], + "links": { + "first": "http://localhost/api/consultants?page=1", + "last": "http://localhost/api/consultants?page=1", + "prev": null, + "next": null + }, + "meta": { + "current_page": 1, + "from": 1, + "last_page": 1, + "links": [], + "path": "http://localhost/api/consultants", + "per_page": 10, + "to": 1, + "total": 1, + "total_min_price": null, + "total_max_price": null + } +} + diff --git a/test/fixtures/feed/diets_pagination_response.json b/test/fixtures/feed/diets_pagination_response.json new file mode 100644 index 00000000..a15de8fb --- /dev/null +++ b/test/fixtures/feed/diets_pagination_response.json @@ -0,0 +1,53 @@ +{ + "data": [ + { + "id": 1, + "slug": "keto-diet", + "name": "Keto Diet", + "image": "https://example.com/keto.jpg", + "duration": 30, + "state": "active", + "type": { + "light": false, + "veg": false, + "carb": false, + "meat": true + }, + "description_md": "Keto diet description", + "daily_schedule": {}, + "author": { + "author_slug": "nutritionist-1", + "author_name": "Nutritionist Name", + "author_profile_icon": "https://example.com/nutritionist.jpg", + "author_is_me": false, + "is_entity_subscribed_by_me": null, + "author_place_in_rating": null + }, + "total_likes": 50, + "total_views": 500, + "total_comments": 25, + "was_liked_by_me": false, + "is_favorite": false, + "daily_nutrition": [] + } + ], + "links": { + "first": "http://localhost/api/diets?page=1", + "last": "http://localhost/api/diets?page=1", + "prev": null, + "next": null + }, + "meta": { + "current_page": 1, + "from": 1, + "last_page": 1, + "links": [], + "path": "http://localhost/api/diets", + "per_page": 10, + "to": 1, + "total": 1, + "total_min_price": null, + "total_max_price": null + } +} + diff --git a/test/fixtures/feed/feed_blog_post_response.json b/test/fixtures/feed/feed_blog_post_response.json new file mode 100644 index 00000000..75ae180b --- /dev/null +++ b/test/fixtures/feed/feed_blog_post_response.json @@ -0,0 +1,23 @@ +{ + "id": 1, + "state": "published", + "image": "https://example.com/image.jpg", + "description": "Описание поста", + "author": { + "author_slug": "author-slug", + "author_name": "Автор", + "author_profile_icon": "https://example.com/photo.jpg", + "author_is_me": false, + "is_entity_subscribed_by_me": null, + "author_place_in_rating": null + }, + "video_url": "", + "created_at": "2024-01-15T12:00:00Z", + "updated_at": "2024-01-15T12:00:00Z", + "title": "Заголовок", + "total_likes": 10, + "total_views": 100, + "total_comments": 5, + "was_liked_by_me": false +} + diff --git a/test/fixtures/feed/feed_blog_posts_settings_response.json b/test/fixtures/feed/feed_blog_posts_settings_response.json new file mode 100644 index 00000000..f8fbf3d4 --- /dev/null +++ b/test/fixtures/feed/feed_blog_posts_settings_response.json @@ -0,0 +1,39 @@ +{ + "data": [ + { + "id": 1, + "state": "published", + "image": "https://example.com/image.jpg", + "description": "Описание поста", + "author": { + "author_slug": "author-slug", + "author_name": "Автор", + "author_profile_icon": "https://example.com/photo.jpg", + "author_is_me": false, + "is_entity_subscribed_by_me": null, + "author_place_in_rating": null + }, + "video_url": "", + "created_at": "2024-01-15T12:00:00Z", + "updated_at": "2024-01-15T12:00:00Z", + "title": "Заголовок", + "total_likes": 10, + "total_views": 100, + "total_comments": 5, + "was_liked_by_me": false + } + ], + "meta": { + "current_page": 1, + "from": 1, + "last_page": 1, + "links": [], + "path": "http://localhost/api/blog-posts", + "per_page": 10, + "to": 1, + "total": 1, + "total_min_price": null, + "total_max_price": null + } +} + diff --git a/test/fixtures/feed/plan_pagination_response.json b/test/fixtures/feed/plan_pagination_response.json new file mode 100644 index 00000000..e67cd788 --- /dev/null +++ b/test/fixtures/feed/plan_pagination_response.json @@ -0,0 +1,63 @@ +{ + "data": [ + { + "id": 1, + "slug": "weight-loss-plan", + "name": "Weight Loss Plan", + "image": "https://example.com/plan.jpg", + "duration": 30, + "state": "active", + "type": { + "fit": false, + "slim": true, + "behavior": false, + "wellness": false + }, + "description_md": "Weight loss plan description", + "packets_count": 3, + "packet1_options": { + "items": ["Item 1", "Item 2"], + "price": 1500.0, + "short": "Option 1", + "description_md": "Description", + "has_personal_diet": false + }, + "packet2_options": null, + "packet3_options": null, + "author": { + "author_slug": "consultant-1", + "author_name": "Consultant Name", + "author_profile_icon": "https://example.com/consultant.jpg", + "author_is_me": false, + "is_entity_subscribed_by_me": null, + "author_place_in_rating": null + }, + "total_likes": 100, + "total_views": 1000, + "total_comments": 50, + "is_favorite": false, + "min_price_of_options": 1000.0, + "max_price_of_options": 5000.0, + "was_liked_by_me": false + } + ], + "links": { + "first": "http://localhost/api/plans?page=1", + "last": "http://localhost/api/plans?page=1", + "prev": null, + "next": null + }, + "meta": { + "current_page": 1, + "from": 1, + "last_page": 1, + "links": [], + "path": "http://localhost/api/plans", + "per_page": 10, + "to": 1, + "total": 1, + "total_min_price": null, + "total_max_price": null + } +} + diff --git a/test/fixtures/feed/recipes_pagination_response.json b/test/fixtures/feed/recipes_pagination_response.json new file mode 100644 index 00000000..8cc60e51 --- /dev/null +++ b/test/fixtures/feed/recipes_pagination_response.json @@ -0,0 +1,53 @@ +{ + "recipes_list": [ + { + "id": 1, + "image": "https://example.com/recipe.jpg", + "state": "published", + "cooking_time": 30, + "active_time": 20, + "ingredients": [ + { + "name": "Pasta", + "unit": "g", + "portion": "200g", + "product_nutritional_id": "1" + } + ], + "description_md": "Test recipe description", + "steps": [ + { + "description": "Step 1", + "image": "https://example.com/step1.jpg" + } + ], + "video_url": "https://example.com/video.mp4", + "created_at": "2024-01-15T12:00:00Z", + "updated_at": "2024-01-15T12:00:00Z", + "title": "Pasta Recipe", + "type": "recipe", + "slug": "pasta-recipe", + "total_comments": 5, + "was_liked_by_me": false, + "is_favorite": false, + "energy_per_serving": 350.0, + "servings": 4, + "total_likes": 20, + "total_views": 150, + "tags": [ + { + "name": "Italian" + } + ], + "author": { + "author_slug": "chef-1", + "author_name": "Chef Name", + "author_profile_icon": "https://example.com/chef.jpg", + "author_is_me": false, + "is_entity_subscribed_by_me": null, + "author_place_in_rating": null + } + } + ] +} + diff --git a/test/fixtures/notifications/notifications_response.json b/test/fixtures/notifications/notifications_response.json new file mode 100644 index 00000000..0cbc6294 --- /dev/null +++ b/test/fixtures/notifications/notifications_response.json @@ -0,0 +1,16 @@ +{ + "notifications": [ + { + "type": "chosen_plan_started_to_client_notification", + "plan_name": "Test Plan", + "plan_id": 1, + "is_read": false, + "created_at": "2024-01-15T12:00:00Z" + } + ], + "pagination": { + "current_page": 1, + "last_page": 1 + } +} + diff --git a/test/fixtures/plans/plan_response.json b/test/fixtures/plans/plan_response.json new file mode 100644 index 00000000..442f799b --- /dev/null +++ b/test/fixtures/plans/plan_response.json @@ -0,0 +1,35 @@ +{ + "id": 1, + "slug": "test-plan", + "name": "Test Plan", + "image": "https://example.com/image.jpg", + "duration": 7, + "state": "active", + "type": { + "fit": true, + "slim": false, + "behavior": false, + "wellness": false + }, + "description_md": "Test details", + "packets_count": 3, + "packet1_options": null, + "packet2_options": null, + "packet3_options": null, + "author": { + "author_slug": "test-author", + "author_name": "Author Name", + "author_profile_icon": "https://example.com/icon.jpg", + "author_is_me": false, + "is_entity_subscribed_by_me": null, + "author_place_in_rating": null + }, + "total_likes": 10, + "total_views": 100, + "total_comments": 5, + "is_favorite": false, + "min_price_of_options": 1000.0, + "max_price_of_options": 2000.0, + "was_liked_by_me": false +} + diff --git a/test/fixtures/recipes/my_recipe_pagination_response.json b/test/fixtures/recipes/my_recipe_pagination_response.json new file mode 100644 index 00000000..9ae8fabd --- /dev/null +++ b/test/fixtures/recipes/my_recipe_pagination_response.json @@ -0,0 +1,25 @@ +{ + "data": [ + { + "id": 1, + "image": "https://someurl.com/img.jpg", + "state": "published", + "cooking_time": 30, + "active_time": 20, + "description_md": "Test recipe description", + "steps": [ + { + "image": "https://someurl.com/step1.jpg", + "description_md": "Step 1 description" + } + ], + "video_url": "https://someurl.com/video.mp4", + "title": "Test Recipe", + "slug": "test-recipe", + "energy_per_serving": 250.0, + "total_likes": 5, + "total_views": 10 + } + ] +} + diff --git a/test/fixtures/recipes/my_recipe_response.json b/test/fixtures/recipes/my_recipe_response.json new file mode 100644 index 00000000..9a9cf40c --- /dev/null +++ b/test/fixtures/recipes/my_recipe_response.json @@ -0,0 +1,21 @@ +{ + "id": 1, + "image": "https://someurl.com/img.jpg", + "state": "published", + "cooking_time": 30, + "active_time": 20, + "description_md": "Test recipe description", + "steps": [ + { + "image": "https://someurl.com/step1.jpg", + "description_md": "Step 1 description" + } + ], + "video_url": "https://someurl.com/video.mp4", + "title": "Test Recipe", + "slug": "test-recipe", + "energy_per_serving": 250.0, + "total_likes": 5, + "total_views": 10 +} + diff --git a/test/fixtures/registration/location_response.json b/test/fixtures/registration/location_response.json new file mode 100644 index 00000000..f9ff7e94 --- /dev/null +++ b/test/fixtures/registration/location_response.json @@ -0,0 +1,8 @@ +{ + "locations": [ + "Москва, Россия", + "Москва, Московская область, Россия" + ], + "response_body": "{\"results\": []}" +} +