From 2408443a26aaac0fda0469499b2b262338ca77b5 Mon Sep 17 00:00:00 2001 From: mso7nueh Date: Thu, 11 Dec 2025 21:43:36 +0300 Subject: [PATCH] test(tests): add whitespace to multiple test files for consistency and improved readability --- test/core/constants/app_constants_test.dart | 1 + test/core/cubit/state_utils_test.dart | 1 + .../core/data/selection_popup_model_test.dart | 1 + test/core/enums/prefs_keys_test.dart | 1 + .../internet_connection_state_test.dart | 1 + test/core/prefs_keys_test.dart | 1 + .../routing/main_navigation_routes_test.dart | 1 + test/core/routing/other_routes_test.dart | 1 + test/core/routing/route_constants_test.dart | 1 + test/core/routing/settings_routes_test.dart | 1 + test/core/views/cubit/views_state_test.dart | 1 + test/core/widgets/add_item_button_test.dart | 1 + .../widgets/animated_option_button_test.dart | 1 + test/core/widgets/base_button_test.dart | 1 + .../widgets/bottom_sheet_with_blur_test.dart | 1 + test/core/widgets/cpfc_container_test.dart | 1 + test/core/widgets/custom_search_bar_test.dart | 1 + test/core/widgets/item_widget_test.dart | 1 + test/core/widgets/loader_test.dart | 1 + .../widgets/main_background_bouble_test.dart | 1 + .../widgets/marketing_bottom_sheet_test.dart | 1 + test/core/widgets/option_widget_test.dart | 1 + .../widgets/rating_history_widget_test.dart | 111 +++++ .../widgets/statistic_widget_test.dart | 91 ++++ .../services/consultation_service_test.dart | 395 ++++++++++++++++++ .../widgets/error_widget_test.dart | 1 + .../chosen_diet_widget_content_test.dart | 1 + .../widgets/comment_container_test.dart | 1 + .../finish_day_button_widget_test.dart | 1 + .../widgets/meal_summary_widget_test.dart | 1 + .../widgets/product_loader_widget_test.dart | 1 + .../cancel_diet_bottom_sheet_test.dart | 98 +++++ .../widgets/info_bouble_test.dart | 1 + .../widgets/start_diet_bottom_sheet_test.dart | 65 +++ .../widgets/choice_chip_widget_test.dart | 1 + .../widgets/filter_badge_test.dart | 1 + .../widgets/status_widget_test.dart | 1 + .../glossary_repository_test.dart | 1 + .../widgets/notification_widget_test.dart | 1 + .../service/notifications_service_test.dart | 1 + .../widgets/collect_charge_banner_test.dart | 132 ++++++ .../widgets/payment_banner_test.dart | 84 ++++ .../presentation/widgets/plan_props_test.dart | 99 +++++ .../presentation/widgets/plan_state_test.dart | 114 +++++ ...personal_diet_suggestion_service_test.dart | 151 +++++++ 45 files changed, 1375 insertions(+) create mode 100644 test/features/consultant_rating/presentation/widgets/rating_history_widget_test.dart create mode 100644 test/features/consultant_rating/presentation/widgets/statistic_widget_test.dart create mode 100644 test/features/consultations/services/consultation_service_test.dart create mode 100644 test/features/diets/presentation/widgets/cancel_diet_bottom_sheet_test.dart create mode 100644 test/features/diets/presentation/widgets/start_diet_bottom_sheet_test.dart create mode 100644 test/features/order_info/presentation/widgets/collect_charge_banner_test.dart create mode 100644 test/features/order_info/presentation/widgets/payment_banner_test.dart create mode 100644 test/features/order_info/presentation/widgets/plan_props_test.dart create mode 100644 test/features/order_info/presentation/widgets/plan_state_test.dart create mode 100644 test/features/personal_diet_suggestion/services/personal_diet_suggestion_service_test.dart diff --git a/test/core/constants/app_constants_test.dart b/test/core/constants/app_constants_test.dart index efd6ba58..0f027609 100644 --- a/test/core/constants/app_constants_test.dart +++ b/test/core/constants/app_constants_test.dart @@ -134,3 +134,4 @@ void main() { + diff --git a/test/core/cubit/state_utils_test.dart b/test/core/cubit/state_utils_test.dart index 0c5206cb..2701e648 100644 --- a/test/core/cubit/state_utils_test.dart +++ b/test/core/cubit/state_utils_test.dart @@ -69,3 +69,4 @@ void main() { + diff --git a/test/core/data/selection_popup_model_test.dart b/test/core/data/selection_popup_model_test.dart index 1ee73a78..55d694a1 100644 --- a/test/core/data/selection_popup_model_test.dart +++ b/test/core/data/selection_popup_model_test.dart @@ -83,3 +83,4 @@ void main() { + diff --git a/test/core/enums/prefs_keys_test.dart b/test/core/enums/prefs_keys_test.dart index 1ee0dd5b..efb5e4a5 100644 --- a/test/core/enums/prefs_keys_test.dart +++ b/test/core/enums/prefs_keys_test.dart @@ -32,3 +32,4 @@ void main() { + diff --git a/test/core/internet_connection_cubit/internet_connection_state_test.dart b/test/core/internet_connection_cubit/internet_connection_state_test.dart index 8ecbae0f..d89cb11a 100644 --- a/test/core/internet_connection_cubit/internet_connection_state_test.dart +++ b/test/core/internet_connection_cubit/internet_connection_state_test.dart @@ -58,3 +58,4 @@ void main() { + diff --git a/test/core/prefs_keys_test.dart b/test/core/prefs_keys_test.dart index bf0441d8..1436f38e 100644 --- a/test/core/prefs_keys_test.dart +++ b/test/core/prefs_keys_test.dart @@ -28,3 +28,4 @@ void main() { + diff --git a/test/core/routing/main_navigation_routes_test.dart b/test/core/routing/main_navigation_routes_test.dart index 6590677b..472e74c2 100644 --- a/test/core/routing/main_navigation_routes_test.dart +++ b/test/core/routing/main_navigation_routes_test.dart @@ -25,3 +25,4 @@ void main() { + diff --git a/test/core/routing/other_routes_test.dart b/test/core/routing/other_routes_test.dart index a92f87be..f00cda2c 100644 --- a/test/core/routing/other_routes_test.dart +++ b/test/core/routing/other_routes_test.dart @@ -29,3 +29,4 @@ void main() { + diff --git a/test/core/routing/route_constants_test.dart b/test/core/routing/route_constants_test.dart index 77876ba7..e4b99b6d 100644 --- a/test/core/routing/route_constants_test.dart +++ b/test/core/routing/route_constants_test.dart @@ -108,3 +108,4 @@ void main() { + diff --git a/test/core/routing/settings_routes_test.dart b/test/core/routing/settings_routes_test.dart index da92ba3e..169e923f 100644 --- a/test/core/routing/settings_routes_test.dart +++ b/test/core/routing/settings_routes_test.dart @@ -32,3 +32,4 @@ void main() { + diff --git a/test/core/views/cubit/views_state_test.dart b/test/core/views/cubit/views_state_test.dart index af486ddd..c23488ad 100644 --- a/test/core/views/cubit/views_state_test.dart +++ b/test/core/views/cubit/views_state_test.dart @@ -26,3 +26,4 @@ void main() { + diff --git a/test/core/widgets/add_item_button_test.dart b/test/core/widgets/add_item_button_test.dart index 4cb8392a..c5e12aed 100644 --- a/test/core/widgets/add_item_button_test.dart +++ b/test/core/widgets/add_item_button_test.dart @@ -62,3 +62,4 @@ void main() { + diff --git a/test/core/widgets/animated_option_button_test.dart b/test/core/widgets/animated_option_button_test.dart index 0d1c1f70..62bc31d9 100644 --- a/test/core/widgets/animated_option_button_test.dart +++ b/test/core/widgets/animated_option_button_test.dart @@ -114,3 +114,4 @@ void main() { + diff --git a/test/core/widgets/base_button_test.dart b/test/core/widgets/base_button_test.dart index 67ad7c6f..18e2821d 100644 --- a/test/core/widgets/base_button_test.dart +++ b/test/core/widgets/base_button_test.dart @@ -51,3 +51,4 @@ void main() { + diff --git a/test/core/widgets/bottom_sheet_with_blur_test.dart b/test/core/widgets/bottom_sheet_with_blur_test.dart index d2a372b0..95c6c225 100644 --- a/test/core/widgets/bottom_sheet_with_blur_test.dart +++ b/test/core/widgets/bottom_sheet_with_blur_test.dart @@ -133,3 +133,4 @@ void main() { + diff --git a/test/core/widgets/cpfc_container_test.dart b/test/core/widgets/cpfc_container_test.dart index 327d0b0e..e45f5b43 100644 --- a/test/core/widgets/cpfc_container_test.dart +++ b/test/core/widgets/cpfc_container_test.dart @@ -94,3 +94,4 @@ void main() { + diff --git a/test/core/widgets/custom_search_bar_test.dart b/test/core/widgets/custom_search_bar_test.dart index 1fe04f59..f75c35e9 100644 --- a/test/core/widgets/custom_search_bar_test.dart +++ b/test/core/widgets/custom_search_bar_test.dart @@ -162,3 +162,4 @@ void main() { + diff --git a/test/core/widgets/item_widget_test.dart b/test/core/widgets/item_widget_test.dart index 22b89920..cba10162 100644 --- a/test/core/widgets/item_widget_test.dart +++ b/test/core/widgets/item_widget_test.dart @@ -55,3 +55,4 @@ void main() { + diff --git a/test/core/widgets/loader_test.dart b/test/core/widgets/loader_test.dart index 91ee1a57..60a6357d 100644 --- a/test/core/widgets/loader_test.dart +++ b/test/core/widgets/loader_test.dart @@ -40,3 +40,4 @@ void main() { + diff --git a/test/core/widgets/main_background_bouble_test.dart b/test/core/widgets/main_background_bouble_test.dart index 540e985a..6cf94449 100644 --- a/test/core/widgets/main_background_bouble_test.dart +++ b/test/core/widgets/main_background_bouble_test.dart @@ -94,3 +94,4 @@ void main() { + diff --git a/test/core/widgets/marketing_bottom_sheet_test.dart b/test/core/widgets/marketing_bottom_sheet_test.dart index 07529f8a..cc57d63a 100644 --- a/test/core/widgets/marketing_bottom_sheet_test.dart +++ b/test/core/widgets/marketing_bottom_sheet_test.dart @@ -74,3 +74,4 @@ void main() { + diff --git a/test/core/widgets/option_widget_test.dart b/test/core/widgets/option_widget_test.dart index 911db47e..fc9d85e9 100644 --- a/test/core/widgets/option_widget_test.dart +++ b/test/core/widgets/option_widget_test.dart @@ -63,3 +63,4 @@ void main() { + diff --git a/test/features/consultant_rating/presentation/widgets/rating_history_widget_test.dart b/test/features/consultant_rating/presentation/widgets/rating_history_widget_test.dart new file mode 100644 index 00000000..4095d408 --- /dev/null +++ b/test/features/consultant_rating/presentation/widgets/rating_history_widget_test.dart @@ -0,0 +1,111 @@ +import 'package:eatvio_app/core/app_config.dart'; +import 'package:eatvio_app/core/app_initializer.dart'; +import 'package:eatvio_app/core/locator_service.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/widgets/loader.dart'; +import 'package:eatvio_app/features/consultant_rating/models/rating_model.dart'; +import 'package:eatvio_app/features/consultant_rating/presentation/widgets/rating_history_widget.dart'; +import 'package:eatvio_app/generated/l10n.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_portal/flutter_portal.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +void main() { + group('RatingHistoryWidget', () { + setUp(() async { + await sl.reset(); + dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); + sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); + }); + + Widget createTestWidget(Widget child) { + return MaterialApp( + theme: ThemeHelper().themeData(), + localizationsDelegates: const [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: const [Locale('ru')], + home: Portal( + child: Scaffold(body: SingleChildScrollView(child: child)), + ), + ); + } + + testWidgets('should display loader when isLoading is true', (WidgetTester tester) async { + // Arrange + const widget = RatingHistoryWidget(isLoading: true, ratingHistory: []); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pump(); + + // Assert + expect(find.byType(Loader), findsOneWidget); + }); + + testWidgets('should display rating history items when isLoading is false', (WidgetTester tester) async { + // Arrange + final ratingHistory = [ + RatingModel( + type: RatingEnum.addedRecipe, + amount: 10, + date: DateTime(2024, 1, 1), + ), + RatingModel( + type: RatingEnum.addedBlogPost, + amount: 5, + date: DateTime(2024, 1, 2), + ), + ]; + final widget = RatingHistoryWidget(isLoading: false, ratingHistory: ratingHistory); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pumpAndSettle(); + + // Assert + expect(find.byType(Loader), findsNothing); + expect(find.byType(ListView), findsOneWidget); + }); + + testWidgets('should display empty list when ratingHistory is empty', (WidgetTester tester) async { + // Arrange + const widget = RatingHistoryWidget(isLoading: false, ratingHistory: []); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pumpAndSettle(); + + // Assert + expect(find.byType(Loader), findsNothing); + expect(find.byType(ListView), findsOneWidget); + }); + + testWidgets('should display all rating types correctly', (WidgetTester tester) async { + // Arrange + final ratingHistory = [ + RatingModel(type: RatingEnum.addedRecipe, amount: 1, date: DateTime.now()), + RatingModel(type: RatingEnum.addedPublicDiet, amount: 2, date: DateTime.now()), + RatingModel(type: RatingEnum.addedBlogPost, amount: 3, date: DateTime.now()), + RatingModel(type: RatingEnum.invitedUser, amount: 4, date: DateTime.now()), + RatingModel(type: RatingEnum.hasMedicalDegree, amount: 5, date: DateTime.now()), + RatingModel(type: RatingEnum.consulted, amount: 6, date: DateTime.now()), + RatingModel(type: RatingEnum.addedGlossary, amount: 7, date: DateTime.now()), + ]; + final widget = RatingHistoryWidget(isLoading: false, ratingHistory: ratingHistory); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pumpAndSettle(); + + // Assert + expect(find.byType(ListView), findsOneWidget); + }); + }); +} + diff --git a/test/features/consultant_rating/presentation/widgets/statistic_widget_test.dart b/test/features/consultant_rating/presentation/widgets/statistic_widget_test.dart new file mode 100644 index 00000000..e85e4624 --- /dev/null +++ b/test/features/consultant_rating/presentation/widgets/statistic_widget_test.dart @@ -0,0 +1,91 @@ +import 'package:eatvio_app/core/app_config.dart'; +import 'package:eatvio_app/core/app_initializer.dart'; +import 'package:eatvio_app/core/locator_service.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/widgets/loader.dart'; +import 'package:eatvio_app/features/consultant_rating/models/statistics_model.dart'; +import 'package:eatvio_app/features/consultant_rating/presentation/widgets/statistic_widget.dart'; +import 'package:eatvio_app/generated/l10n.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_portal/flutter_portal.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +void main() { + group('StatisticWidget', () { + setUp(() async { + await sl.reset(); + dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); + sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); + }); + + Widget createTestWidget(Widget child) { + return MaterialApp( + theme: ThemeHelper().themeData(), + localizationsDelegates: const [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: const [Locale('ru')], + home: Portal( + child: Scaffold(body: SingleChildScrollView(child: child)), + ), + ); + } + + testWidgets('should display loader when isLoading is true', (WidgetTester tester) async { + // Arrange + const widget = StatisticWidget(isLoading: true, statistics: null); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pump(); + + // Assert + expect(find.byType(Loader), findsOneWidget); + }); + + testWidgets('should display statistics when isLoading is false and statistics provided', (WidgetTester tester) async { + // Arrange + final statistics = StatisticsModel( + countReferal: 10, + blogPostsCount: 5, + recipesCount: 3, + dietsCount: 2, + consultationsCount: 8, + qwe: 1, + ); + final widget = StatisticWidget(isLoading: false, statistics: statistics); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pumpAndSettle(); + + // Assert + expect(find.byType(Loader), findsNothing); + expect(find.text('10'), findsOneWidget); + expect(find.text('5'), findsOneWidget); + expect(find.text('3'), findsOneWidget); + expect(find.text('2'), findsOneWidget); + expect(find.text('8'), findsOneWidget); + expect(find.text('1'), findsOneWidget); + }); + + testWidgets('should display zeros when statistics is null', (WidgetTester tester) async { + // Arrange + const widget = StatisticWidget(isLoading: false, statistics: null); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pumpAndSettle(); + + // Assert + expect(find.byType(Loader), findsNothing); + expect(find.text('0'), findsNWidgets(6)); + }); + }); +} + 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..af8be000 --- /dev/null +++ b/test/features/consultations/services/consultation_service_test.dart @@ -0,0 +1,395 @@ +import 'package:dio/dio.dart'; +import 'package:eatvio_app/core/enums/filters_comparison_enum.dart'; +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 'consultation_service_test.mocks.dart'; + +@GenerateMocks([Dio]) +void main() { + group('ConsultationService', () { + late ConsultationService service; + late MockDio mockDio; + + setUp(() { + mockDio = MockDio(); + service = ConsultationService(mockDio); + }); + + test('getConsultations - успешное получение консультаций', () async { + final mockData = { + 'data': [], + 'links': {}, + 'meta': { + 'current_page': 1, + 'last_page': 1, + 'total': 0, + 'per_page': 10, + }, + }; + + when(mockDio.get( + '/api/consultations', + queryParameters: anyNamed('queryParameters'), + )).thenAnswer((_) async => Response( + requestOptions: RequestOptions(path: '/api/consultations'), + statusCode: 200, + data: mockData, + )); + + final result = await service.getConsultations(); + + expect(result, isA()); + verify(mockDio.get( + '/api/consultations', + queryParameters: { + 'filters[last_state][\$notIn][]': const [ + 'initied', + 'in_coordination', + 'start_date_has_been_set', + 'pending_payment', + 'canceled_by_the_initiator', + 'charge_was_collected', + ], + 'sort[]': 'created_at:desc' + }, + )).called(1); + }); + + test('getConsultations - пробрасывает ошибку', () async { + when(mockDio.get( + any, + queryParameters: anyNamed('queryParameters'), + )).thenThrow(DioException( + requestOptions: RequestOptions(path: '/api/consultations'), + )); + + expect(() => service.getConsultations(), throwsA(isA())); + }); + + test('getFilteredConsultations - успешное получение с фильтрами notInArray', () async { + final mockData = { + 'data': [], + 'links': {}, + 'meta': { + 'current_page': 1, + 'last_page': 1, + 'total': 0, + 'per_page': 10, + }, + }; + + when(mockDio.get( + '/api/consultations', + queryParameters: anyNamed('queryParameters'), + )).thenAnswer((_) async => Response( + requestOptions: RequestOptions(path: '/api/consultations'), + statusCode: 200, + data: mockData, + )); + + final result = await service.getFilteredConsultations( + stateComparison: FiltersComparisonEnum.notInArray, + ); + + expect(result, isA()); + verify(mockDio.get( + '/api/consultations', + queryParameters: { + 'filters[last_state][\$notIn][]': const [ + 'initied', + 'in_coordination', + 'start_date_has_been_set', + 'pending_payment', + 'canceled_by_the_initiator', + 'charge_was_collected', + ], + 'sort[]': 'created_at:desc', + }, + )).called(1); + }); + + test('getFilteredConsultations - успешное получение с фильтром state', () async { + final mockData = { + 'data': [], + 'links': {}, + 'meta': { + 'current_page': 1, + 'last_page': 1, + 'total': 0, + 'per_page': 10, + }, + }; + + when(mockDio.get( + '/api/consultations', + queryParameters: anyNamed('queryParameters'), + )).thenAnswer((_) async => Response( + requestOptions: RequestOptions(path: '/api/consultations'), + statusCode: 200, + data: mockData, + )); + + final result = await service.getFilteredConsultations( + state: 'done', + stateComparison: FiltersComparisonEnum.equal, + ); + + expect(result, isA()); + verify(mockDio.get( + '/api/consultations', + queryParameters: { + 'filters[last_state][\$eq]': 'done', + 'sort[]': 'created_at:desc', + }, + )).called(1); + }); + + test('getFilteredConsultations - успешное получение с фильтром date', () async { + final mockData = { + 'data': [], + 'links': {}, + 'meta': { + 'current_page': 1, + 'last_page': 1, + 'total': 0, + 'per_page': 10, + }, + }; + + when(mockDio.get( + '/api/consultations', + queryParameters: anyNamed('queryParameters'), + )).thenAnswer((_) async => Response( + requestOptions: RequestOptions(path: '/api/consultations'), + statusCode: 200, + data: mockData, + )); + + final result = await service.getFilteredConsultations( + date: '2024-01-01', + dateComparison: FiltersComparisonEnum.greaterThan, + ); + + expect(result, isA()); + verify(mockDio.get( + '/api/consultations', + queryParameters: { + 'filters[start_date][\$gt]': '2024-01-01', + 'sort[]': 'created_at:desc', + }, + )).called(1); + }); + + test('getFilteredConsultations - пробрасывает ошибку', () async { + when(mockDio.get( + any, + queryParameters: anyNamed('queryParameters'), + )).thenThrow(DioException( + requestOptions: RequestOptions(path: '/api/consultations'), + )); + + expect( + () => service.getFilteredConsultations(), + throwsA(isA()), + ); + }); + + test('getStatistics - успешное получение статистики', () async { + final mockData = { + 'total': 10, + 'in_progress': 5, + 'finished': 3, + 'canceled': 2, + }; + + when(mockDio.get('/api/consultations/statistics')).thenAnswer((_) async => Response( + requestOptions: RequestOptions(path: '/api/consultations/statistics'), + statusCode: 200, + data: mockData, + )); + + final result = await service.getStatistics(); + + expect(result, isA()); + expect(result.total, 10); + expect(result.inProgress, 5); + expect(result.finished, 3); + expect(result.canceled, 2); + verify(mockDio.get('/api/consultations/statistics')).called(1); + }); + + test('getStatistics - пробрасывает ошибку', () async { + when(mockDio.get('/api/consultations/statistics')).thenThrow(DioException( + requestOptions: RequestOptions(path: '/api/consultations/statistics'), + )); + + expect(() => service.getStatistics(), throwsA(isA())); + }); + + test('getConsultantFinances - успешное получение финансов', () async { + final mockData = { + 'data': [ + { + 'start_date': '2024-01-01T00:00:00Z', + 'bank_id': 'bank-1', + 'title': 'Consultation', + 'clientName': 'Client Name', + 'duration': 60, + 'payment_price': 100000, + 'payment_status': 'COMPLETED', + } + ], + }; + + when(mockDio.get( + '/api/finances/my_finances', + queryParameters: anyNamed('queryParameters'), + )).thenAnswer((_) async => Response( + requestOptions: RequestOptions(path: '/api/finances/my_finances'), + statusCode: 200, + data: mockData, + )); + + final result = await service.getConsultantFinances(null, null); + + expect(result, isA>()); + expect(result.length, 1); + verify(mockDio.get( + '/api/finances/my_finances', + queryParameters: { + 'sort[]': 'start_date:desc', + }, + )).called(1); + }); + + test('getConsultantFinances - успешное получение с фильтром date', () async { + final mockData = { + 'data': [], + }; + + when(mockDio.get( + '/api/finances/my_finances', + queryParameters: anyNamed('queryParameters'), + )).thenAnswer((_) async => Response( + requestOptions: RequestOptions(path: '/api/finances/my_finances'), + statusCode: 200, + data: mockData, + )); + + final result = await service.getConsultantFinances( + '2024-01-01', + FiltersComparisonEnum.equal, + ); + + expect(result, isA>()); + verify(mockDio.get( + '/api/finances/my_finances', + queryParameters: { + 'filters[start_date][\$eq]': '2024-01-01', + 'sort[]': 'start_date:desc', + }, + )).called(1); + }); + + test('getConsultantFinances - пробрасывает ошибку', () async { + when(mockDio.get( + any, + queryParameters: anyNamed('queryParameters'), + )).thenThrow(DioException( + requestOptions: RequestOptions(path: '/api/finances/my_finances'), + )); + + expect( + () => service.getConsultantFinances(null, null), + throwsA(isA()), + ); + }); + + test('getUserPurchases - успешное получение покупок', () async { + final mockData = { + 'data': [ + { + 'start_date': '2024-01-01T00:00:00Z', + 'bank_id': 'bank-1', + 'title': 'Plan Title', + 'consultantName': 'Consultant Name', + 'duration': 30, + 'price': 1000, + 'chosen_plan_last_state': 'paid', + } + ], + }; + + when(mockDio.get( + '/api/finances/my_purchases', + queryParameters: anyNamed('queryParameters'), + )).thenAnswer((_) async => Response( + requestOptions: RequestOptions(path: '/api/finances/my_purchases'), + statusCode: 200, + data: mockData, + )); + + final result = await service.getUserPurchases(null, null); + + expect(result, isA>()); + expect(result.length, 1); + verify(mockDio.get( + '/api/finances/my_purchases', + queryParameters: { + 'sort[]': 'start_date:desc', + }, + )).called(1); + }); + + test('getUserPurchases - успешное получение с фильтром date', () async { + final mockData = { + 'data': [], + }; + + when(mockDio.get( + '/api/finances/my_purchases', + queryParameters: anyNamed('queryParameters'), + )).thenAnswer((_) async => Response( + requestOptions: RequestOptions(path: '/api/finances/my_purchases'), + statusCode: 200, + data: mockData, + )); + + final result = await service.getUserPurchases( + '2024-01-01', + FiltersComparisonEnum.greaterThan, + ); + + expect(result, isA>()); + verify(mockDio.get( + '/api/finances/my_purchases', + queryParameters: { + 'filters[start_date][\$gt]': '2024-01-01', + 'sort[]': 'start_date:desc', + }, + )).called(1); + }); + + test('getUserPurchases - пробрасывает ошибку', () async { + when(mockDio.get( + any, + queryParameters: anyNamed('queryParameters'), + )).thenThrow(DioException( + requestOptions: RequestOptions(path: '/api/finances/my_purchases'), + )); + + expect( + () => service.getUserPurchases(null, null), + throwsA(isA()), + ); + }); + }); +} + diff --git a/test/features/create_diet/presentation/widgets/error_widget_test.dart b/test/features/create_diet/presentation/widgets/error_widget_test.dart index d60b3cb7..a3b8c252 100644 --- a/test/features/create_diet/presentation/widgets/error_widget_test.dart +++ b/test/features/create_diet/presentation/widgets/error_widget_test.dart @@ -69,3 +69,4 @@ void main() { + diff --git a/test/features/diary/presentation/widgets/chosen_diet_widget_content_test.dart b/test/features/diary/presentation/widgets/chosen_diet_widget_content_test.dart index 7d8092b6..40bb41da 100644 --- a/test/features/diary/presentation/widgets/chosen_diet_widget_content_test.dart +++ b/test/features/diary/presentation/widgets/chosen_diet_widget_content_test.dart @@ -78,3 +78,4 @@ void main() { + diff --git a/test/features/diary/presentation/widgets/comment_container_test.dart b/test/features/diary/presentation/widgets/comment_container_test.dart index 318b6ba5..6e50f17a 100644 --- a/test/features/diary/presentation/widgets/comment_container_test.dart +++ b/test/features/diary/presentation/widgets/comment_container_test.dart @@ -56,3 +56,4 @@ void main() { + diff --git a/test/features/diary/presentation/widgets/finish_day_button_widget_test.dart b/test/features/diary/presentation/widgets/finish_day_button_widget_test.dart index d973ef2e..a4aa5822 100644 --- a/test/features/diary/presentation/widgets/finish_day_button_widget_test.dart +++ b/test/features/diary/presentation/widgets/finish_day_button_widget_test.dart @@ -51,3 +51,4 @@ void main() { + diff --git a/test/features/diary/presentation/widgets/meal_summary_widget_test.dart b/test/features/diary/presentation/widgets/meal_summary_widget_test.dart index 8300178e..d9c7d707 100644 --- a/test/features/diary/presentation/widgets/meal_summary_widget_test.dart +++ b/test/features/diary/presentation/widgets/meal_summary_widget_test.dart @@ -88,3 +88,4 @@ void main() { + diff --git a/test/features/diary/presentation/widgets/product_loader_widget_test.dart b/test/features/diary/presentation/widgets/product_loader_widget_test.dart index 43312df1..8fcdcd78 100644 --- a/test/features/diary/presentation/widgets/product_loader_widget_test.dart +++ b/test/features/diary/presentation/widgets/product_loader_widget_test.dart @@ -40,3 +40,4 @@ void main() { + diff --git a/test/features/diets/presentation/widgets/cancel_diet_bottom_sheet_test.dart b/test/features/diets/presentation/widgets/cancel_diet_bottom_sheet_test.dart new file mode 100644 index 00000000..f808123b --- /dev/null +++ b/test/features/diets/presentation/widgets/cancel_diet_bottom_sheet_test.dart @@ -0,0 +1,98 @@ +import 'package:eatvio_app/core/app_config.dart'; +import 'package:eatvio_app/core/app_initializer.dart'; +import 'package:eatvio_app/core/locator_service.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; +import 'package:eatvio_app/features/diets/presentation/cubit/about_diet_cubit.dart'; +import 'package:eatvio_app/features/diets/presentation/widgets/cancel_diet_bottom_sheet.dart'; +import 'package:eatvio_app/generated/l10n.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_portal/flutter_portal.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'cancel_diet_bottom_sheet_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('CancelDietBottomSheet', () { + setUp(() async { + await sl.reset(); + dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); + sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); + }); + + Widget createTestWidget(Widget child, AboutDietCubit cubit) { + return MaterialApp( + theme: ThemeHelper().themeData(), + localizationsDelegates: const [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: const [Locale('ru')], + home: Portal( + child: BlocProvider( + create: (_) => cubit, + child: Scaffold(body: child), + ), + ), + ); + } + + testWidgets('should display cancel diet bottom sheet with default title', (WidgetTester tester) async { + // Arrange + final mockCubit = MockAboutDietCubit(); + final widget = CancelDietBottomSheet( + aboutDietCubit: mockCubit, + ); + + // Act + await tester.pumpWidget(createTestWidget(widget, mockCubit)); + await tester.pump(); + + // Assert + expect(find.byType(CancelDietBottomSheet), findsOneWidget); + expect(find.byType(CustomOutlinedButton), findsOneWidget); + }); + + testWidgets('should display cancel diet bottom sheet with custom title', (WidgetTester tester) async { + // Arrange + final mockCubit = MockAboutDietCubit(); + final widget = CancelDietBottomSheet( + aboutDietCubit: mockCubit, + title: 'Custom title', + ); + + // Act + await tester.pumpWidget(createTestWidget(widget, mockCubit)); + await tester.pump(); + + // Assert + expect(find.byType(CancelDietBottomSheet), findsOneWidget); + expect(find.text('Custom title'), findsOneWidget); + }); + + testWidgets('should display cancel diet bottom sheet with diet name', (WidgetTester tester) async { + // Arrange + final mockCubit = MockAboutDietCubit(); + final widget = CancelDietBottomSheet( + aboutDietCubit: mockCubit, + dietName: 'Test Diet', + ); + + // Act + await tester.pumpWidget(createTestWidget(widget, mockCubit)); + await tester.pump(); + + // Assert + expect(find.byType(CancelDietBottomSheet), findsOneWidget); + }); + }); +} + diff --git a/test/features/diets/presentation/widgets/info_bouble_test.dart b/test/features/diets/presentation/widgets/info_bouble_test.dart index 77b036ff..6d79b9b3 100644 --- a/test/features/diets/presentation/widgets/info_bouble_test.dart +++ b/test/features/diets/presentation/widgets/info_bouble_test.dart @@ -106,3 +106,4 @@ void main() { + diff --git a/test/features/diets/presentation/widgets/start_diet_bottom_sheet_test.dart b/test/features/diets/presentation/widgets/start_diet_bottom_sheet_test.dart new file mode 100644 index 00000000..f0bf9d6a --- /dev/null +++ b/test/features/diets/presentation/widgets/start_diet_bottom_sheet_test.dart @@ -0,0 +1,65 @@ +import 'package:eatvio_app/core/app_config.dart'; +import 'package:eatvio_app/core/app_initializer.dart'; +import 'package:eatvio_app/core/locator_service.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; +import 'package:eatvio_app/features/diets/presentation/cubit/about_diet_cubit.dart'; +import 'package:eatvio_app/features/diets/presentation/widgets/start_diet_bottom_sheet.dart'; +import 'package:eatvio_app/generated/l10n.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_portal/flutter_portal.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'start_diet_bottom_sheet_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('StartDietBottomSheet', () { + setUp(() async { + await sl.reset(); + dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); + sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); + }); + + Widget createTestWidget(Widget child, AboutDietCubit cubit) { + return MaterialApp( + theme: ThemeHelper().themeData(), + localizationsDelegates: const [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: const [Locale('ru')], + home: Portal( + child: BlocProvider( + create: (_) => cubit, + child: Scaffold(body: child), + ), + ), + ); + } + + testWidgets('should display start diet bottom sheet', (WidgetTester tester) async { + // Arrange + final mockCubit = MockAboutDietCubit(); + final widget = StartDietBottomSheet( + aboutDietCubit: mockCubit, + ); + + // Act + await tester.pumpWidget(createTestWidget(widget, mockCubit)); + await tester.pump(); + + // Assert + expect(find.byType(StartDietBottomSheet), findsOneWidget); + expect(find.byType(CustomOutlinedButton), findsOneWidget); + }); + }); +} + diff --git a/test/features/feed/presentation/widgets/choice_chip_widget_test.dart b/test/features/feed/presentation/widgets/choice_chip_widget_test.dart index 5d684826..e59afedf 100644 --- a/test/features/feed/presentation/widgets/choice_chip_widget_test.dart +++ b/test/features/feed/presentation/widgets/choice_chip_widget_test.dart @@ -136,3 +136,4 @@ void main() { + diff --git a/test/features/feed/presentation/widgets/filter_badge_test.dart b/test/features/feed/presentation/widgets/filter_badge_test.dart index dbd34016..886c3f2a 100644 --- a/test/features/feed/presentation/widgets/filter_badge_test.dart +++ b/test/features/feed/presentation/widgets/filter_badge_test.dart @@ -48,3 +48,4 @@ void main() { + diff --git a/test/features/finances_and_consultations_archive/presentation/widgets/status_widget_test.dart b/test/features/finances_and_consultations_archive/presentation/widgets/status_widget_test.dart index e391feb8..55bf71af 100644 --- a/test/features/finances_and_consultations_archive/presentation/widgets/status_widget_test.dart +++ b/test/features/finances_and_consultations_archive/presentation/widgets/status_widget_test.dart @@ -56,3 +56,4 @@ void main() { + diff --git a/test/features/glossary/repositories/glossary_repository_test.dart b/test/features/glossary/repositories/glossary_repository_test.dart index 7f4c0fa5..acc91a91 100644 --- a/test/features/glossary/repositories/glossary_repository_test.dart +++ b/test/features/glossary/repositories/glossary_repository_test.dart @@ -49,3 +49,4 @@ void main() { + diff --git a/test/features/notifications/presentation/widgets/notification_widget_test.dart b/test/features/notifications/presentation/widgets/notification_widget_test.dart index 7b7ec20a..4b2c42b6 100644 --- a/test/features/notifications/presentation/widgets/notification_widget_test.dart +++ b/test/features/notifications/presentation/widgets/notification_widget_test.dart @@ -1026,3 +1026,4 @@ void main() { + diff --git a/test/features/notifications/service/notifications_service_test.dart b/test/features/notifications/service/notifications_service_test.dart index 375bf276..48c85c71 100644 --- a/test/features/notifications/service/notifications_service_test.dart +++ b/test/features/notifications/service/notifications_service_test.dart @@ -174,3 +174,4 @@ void main() { + diff --git a/test/features/order_info/presentation/widgets/collect_charge_banner_test.dart b/test/features/order_info/presentation/widgets/collect_charge_banner_test.dart new file mode 100644 index 00000000..046e4c41 --- /dev/null +++ b/test/features/order_info/presentation/widgets/collect_charge_banner_test.dart @@ -0,0 +1,132 @@ +import 'package:eatvio_app/core/app_config.dart'; +import 'package:eatvio_app/core/app_initializer.dart'; +import 'package:eatvio_app/core/locator_service.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; +import 'package:eatvio_app/features/order_info/presentation/widgets/collect_charge_banner.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' show PlanModel, PlanType; +import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart' show Author; +import 'package:eatvio_app/generated/l10n.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_portal/flutter_portal.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:go_router/go_router.dart'; + +void main() { + group('CollectChargeBanner', () { + setUp(() async { + await sl.reset(); + dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); + sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); + }); + + Widget createTestWidget(Widget child) { + return MaterialApp.router( + theme: ThemeHelper().themeData(), + localizationsDelegates: const [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: const [Locale('ru')], + routerConfig: GoRouter( + routes: [ + GoRoute( + path: '/', + builder: (context, state) => Portal( + child: Scaffold(body: SingleChildScrollView(child: child)), + ), + ), + ], + ), + ); + } + + testWidgets('should display collect charge banner with plan name and price', (WidgetTester tester) async { + // Arrange + final chosenPlan = ChosenPlanModel( + id: 1, + optionType: 'standard', + startDate: DateTime.now(), + chosenPlanState: ChosenPlanStateEnum.stateDone, + chatId: 'chat-1', + consultantId: 1, + plan: const PlanModel( + id: 1, + slug: 'test-plan', + name: 'Test Plan', + image: 'test.jpg', + duration: 30, + state: 'active', + type: PlanType(fit: true, slim: false, behavior: false, wellness: false), + details: 'Test details', + packetsCount: 1, + author: Author(authorSlug: '', authorName: '', authorProfileIcon: '', authorIsMe: false), + totalLikes: 0, + totalViews: 0, + totalComments: 0, + isFavorite: false, + minPriceOfOptions: 100.0, + maxPriceOfOptions: 500.0, + wasLikedByMe: false, + ), + ); + const price = 1000.0; + final widget = CollectChargeBanner(chosenPlan: chosenPlan, price: price); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pump(); + + // Assert + expect(find.byType(CollectChargeBanner), findsOneWidget); + expect(find.byType(CustomOutlinedButton), findsOneWidget); + }); + + testWidgets('should have button that navigates to card settings', (WidgetTester tester) async { + // Arrange + final chosenPlan = ChosenPlanModel( + id: 1, + optionType: 'standard', + startDate: DateTime.now(), + chosenPlanState: ChosenPlanStateEnum.stateDone, + chatId: 'chat-1', + consultantId: 1, + plan: const PlanModel( + id: 1, + slug: 'test-plan', + name: 'Test Plan', + image: 'test.jpg', + duration: 30, + state: 'active', + type: PlanType(fit: true, slim: false, behavior: false, wellness: false), + details: 'Test details', + packetsCount: 1, + author: Author(authorSlug: '', authorName: '', authorProfileIcon: '', authorIsMe: false), + totalLikes: 0, + totalViews: 0, + totalComments: 0, + isFavorite: false, + minPriceOfOptions: 100.0, + maxPriceOfOptions: 500.0, + wasLikedByMe: false, + ), + ); + const price = 1000.0; + final widget = CollectChargeBanner(chosenPlan: chosenPlan, price: price); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pump(); + + // Assert - проверяем, что кнопка существует + expect(find.byType(CustomOutlinedButton), findsOneWidget); + }); + }); +} + diff --git a/test/features/order_info/presentation/widgets/payment_banner_test.dart b/test/features/order_info/presentation/widgets/payment_banner_test.dart new file mode 100644 index 00000000..4ead1d27 --- /dev/null +++ b/test/features/order_info/presentation/widgets/payment_banner_test.dart @@ -0,0 +1,84 @@ +import 'package:eatvio_app/core/app_config.dart'; +import 'package:eatvio_app/core/app_initializer.dart'; +import 'package:eatvio_app/core/locator_service.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; +import 'package:eatvio_app/core/widgets/loader.dart'; +import 'package:eatvio_app/features/order_info/cubit/order_info_cubit.dart'; +import 'package:eatvio_app/features/order_info/presentation/widgets/payment_banner.dart'; +import 'package:eatvio_app/generated/l10n.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_portal/flutter_portal.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:go_router/go_router.dart'; + +import 'payment_banner_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('PaymentBanner', () { + setUp(() async { + await sl.reset(); + dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); + sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); + }); + + Widget createTestWidget(Widget child, OrderInfoCubit cubit) { + return MaterialApp.router( + theme: ThemeHelper().themeData(), + localizationsDelegates: const [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: const [Locale('ru')], + routerConfig: GoRouter( + routes: [ + GoRoute( + path: '/', + builder: (context, state) => Portal( + child: BlocProvider( + create: (_) => cubit, + child: Scaffold(body: SingleChildScrollView(child: child)), + ), + ), + ), + ], + ), + ); + } + + testWidgets('should display payment banner with successful payment', (WidgetTester tester) async { + // Arrange + final mockCubit = MockOrderInfoCubit(); + const widget = PaymentBanner(successfulPayment: true); + + // Act + await tester.pumpWidget(createTestWidget(widget, mockCubit)); + await tester.pump(); + + // Assert + expect(find.byType(PaymentBanner), findsOneWidget); + }); + + testWidgets('should display payment banner with failed payment', (WidgetTester tester) async { + // Arrange + final mockCubit = MockOrderInfoCubit(); + const widget = PaymentBanner(successfulPayment: false); + + // Act + await tester.pumpWidget(createTestWidget(widget, mockCubit)); + await tester.pump(); + + // Assert + expect(find.byType(PaymentBanner), findsOneWidget); + }); + }); +} + diff --git a/test/features/order_info/presentation/widgets/plan_props_test.dart b/test/features/order_info/presentation/widgets/plan_props_test.dart new file mode 100644 index 00000000..8d85e220 --- /dev/null +++ b/test/features/order_info/presentation/widgets/plan_props_test.dart @@ -0,0 +1,99 @@ +import 'package:eatvio_app/core/app_config.dart'; +import 'package:eatvio_app/core/app_initializer.dart'; +import 'package:eatvio_app/core/locator_service.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/features/order_info/presentation/widgets/plan_props.dart'; +import 'package:eatvio_app/features/order_info/presentation/widgets/plan_status_box.dart'; +import 'package:eatvio_app/generated/l10n.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_portal/flutter_portal.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +void main() { + group('PlanProps', () { + setUp(() async { + await sl.reset(); + dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); + sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); + }); + + Widget createTestWidget(Widget child) { + return MaterialApp( + theme: ThemeHelper().themeData(), + localizationsDelegates: const [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: const [Locale('ru')], + home: Portal( + child: Scaffold(body: SingleChildScrollView(child: child)), + ), + ); + } + + testWidgets('should display plan props with all information', (WidgetTester tester) async { + // Arrange + const planDuration = 30; + const planPrice = 1000.0; + const planStatus = PlanStatusValues.paid; + const widget = PlanProps( + planDuration: planDuration, + planPrice: planPrice, + planStatus: planStatus, + ); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pump(); + + // Assert + expect(find.byType(PlanProps), findsOneWidget); + expect(find.byType(PlanStatusBox), findsOneWidget); + }); + + testWidgets('should display plan props with pending payment status', (WidgetTester tester) async { + // Arrange + const planDuration = 15; + const planPrice = 500.0; + const planStatus = PlanStatusValues.pendingPayment; + const widget = PlanProps( + planDuration: planDuration, + planPrice: planPrice, + planStatus: planStatus, + ); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pump(); + + // Assert + expect(find.byType(PlanProps), findsOneWidget); + expect(find.byType(PlanStatusBox), findsOneWidget); + }); + + testWidgets('should display plan props with payment failed status', (WidgetTester tester) async { + // Arrange + const planDuration = 7; + const planPrice = 200.0; + const planStatus = PlanStatusValues.paymentFailed; + const widget = PlanProps( + planDuration: planDuration, + planPrice: planPrice, + planStatus: planStatus, + ); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pump(); + + // Assert + expect(find.byType(PlanProps), findsOneWidget); + expect(find.byType(PlanStatusBox), findsOneWidget); + }); + }); +} + diff --git a/test/features/order_info/presentation/widgets/plan_state_test.dart b/test/features/order_info/presentation/widgets/plan_state_test.dart new file mode 100644 index 00000000..68862e25 --- /dev/null +++ b/test/features/order_info/presentation/widgets/plan_state_test.dart @@ -0,0 +1,114 @@ +import 'package:eatvio_app/core/app_config.dart'; +import 'package:eatvio_app/core/app_initializer.dart'; +import 'package:eatvio_app/core/locator_service.dart'; +import 'package:eatvio_app/core/theme/theme_helper.dart'; +import 'package:eatvio_app/features/order_info/presentation/widgets/plan_state.dart'; +import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart'; +import 'package:eatvio_app/generated/l10n.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_portal/flutter_portal.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; + +void main() { + group('PlanState', () { + setUp(() async { + await sl.reset(); + dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); + sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); + }); + + Widget createTestWidget(Widget child) { + return MaterialApp( + theme: ThemeHelper().themeData(), + localizationsDelegates: const [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: const [Locale('ru')], + home: Portal( + child: Scaffold(body: SingleChildScrollView(child: child)), + ), + ); + } + + testWidgets('should display plan state without personal diet', (WidgetTester tester) async { + // Arrange + const widget = PlanState( + state: ChosenPlanStateEnum.statePaid, + hasPersonalDiet: false, + ); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pump(); + + // Assert + expect(find.byType(PlanState), findsOneWidget); + }); + + testWidgets('should display plan state with personal diet', (WidgetTester tester) async { + // Arrange + const widget = PlanState( + state: ChosenPlanStateEnum.statePaid, + hasPersonalDiet: true, + ); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pump(); + + // Assert + expect(find.byType(PlanState), findsOneWidget); + }); + + testWidgets('should display different states correctly', (WidgetTester tester) async { + // Arrange + const widget = PlanState( + state: ChosenPlanStateEnum.stateInProgress, + hasPersonalDiet: false, + ); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pump(); + + // Assert + expect(find.byType(PlanState), findsOneWidget); + }); + + testWidgets('should display done state', (WidgetTester tester) async { + // Arrange + const widget = PlanState( + state: ChosenPlanStateEnum.stateDone, + hasPersonalDiet: false, + ); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pump(); + + // Assert + expect(find.byType(PlanState), findsOneWidget); + }); + + testWidgets('should display state with personal diet set', (WidgetTester tester) async { + // Arrange + const widget = PlanState( + state: ChosenPlanStateEnum.personalDietSet, + hasPersonalDiet: true, + ); + + // Act + await tester.pumpWidget(createTestWidget(widget)); + await tester.pump(); + + // Assert + expect(find.byType(PlanState), findsOneWidget); + }); + }); +} + 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..ef33e11f --- /dev/null +++ b/test/features/personal_diet_suggestion/services/personal_diet_suggestion_service_test.dart @@ -0,0 +1,151 @@ +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 'personal_diet_suggestion_service_test.mocks.dart'; + +@GenerateMocks([Dio]) +void main() { + group('PersonalDietSuggestionService', () { + late PersonalDietSuggestionService service; + late MockDio mockDio; + + setUp(() { + mockDio = MockDio(); + service = PersonalDietSuggestionService(mockDio); + }); + + test('getConsultationWithPersonalDiets - успешное получение консультаций', () async { + final mockData = { + 'data': [], + 'links': {}, + 'meta': { + 'current_page': 1, + 'last_page': 1, + 'total': 0, + 'per_page': 10, + }, + }; + + when(mockDio.get( + '/api/consultations', + queryParameters: anyNamed('queryParameters'), + )).thenAnswer((_) async => Response( + requestOptions: RequestOptions(path: '/api/consultations'), + statusCode: 200, + data: mockData, + )); + + final result = await service.getConsultationWithPersonalDiets(); + + expect(result, isA()); + verify(mockDio.get( + '/api/consultations', + queryParameters: { + 'filters[plan][has_personal_diet][\$personal_diet]': '1', + 'filters[last_state][\$notIn][]': [ + 'done', + 'charge_was_collected', + 'complained', + 'last_day_finished', + 'canceled_by_the_initiator', + 'inited' + ], + 'sort[]': 'start_date:desc', + }, + )).called(1); + }); + + test('getConsultationWithPersonalDiets - пробрасывает ошибку', () async { + when(mockDio.get( + any, + queryParameters: anyNamed('queryParameters'), + )).thenThrow(DioException( + requestOptions: RequestOptions(path: '/api/consultations'), + )); + + expect( + () => service.getConsultationWithPersonalDiets(), + throwsA(isA()), + ); + }); + + test('attachPersonalDiet - успешное прикрепление диеты', () async { + const consultationId = 1; + const dietId = 2; + + when(mockDio.post( + '/api/chosen_plans/$consultationId/attach_diet', + data: anyNamed('data'), + )).thenAnswer((_) async => Response( + requestOptions: RequestOptions(path: '/api/chosen_plans/$consultationId/attach_diet'), + statusCode: 200, + )); + + await service.attachPersonalDiet(consultationId: consultationId, dietId: dietId); + + verify(mockDio.post( + '/api/chosen_plans/$consultationId/attach_diet', + data: {'diet_id': dietId}, + )).called(1); + }); + + test('attachPersonalDiet - пробрасывает ошибку', () async { + const consultationId = 1; + const dietId = 2; + + when(mockDio.post( + any, + data: anyNamed('data'), + )).thenThrow(DioException( + requestOptions: RequestOptions(path: '/api/chosen_plans/$consultationId/attach_diet'), + )); + + expect( + () => service.attachPersonalDiet(consultationId: consultationId, dietId: dietId), + throwsA(isA()), + ); + }); + + test('reattachPersonalDiet - успешное повторное прикрепление диеты', () async { + const consultationId = 1; + const dietId = 3; + + when(mockDio.post( + '/api/chosen_plans/$consultationId/re_attach_diet', + data: anyNamed('data'), + )).thenAnswer((_) async => Response( + requestOptions: RequestOptions(path: '/api/chosen_plans/$consultationId/re_attach_diet'), + statusCode: 200, + )); + + await service.reattachPersonalDiet(consultationId: consultationId, dietId: dietId); + + verify(mockDio.post( + '/api/chosen_plans/$consultationId/re_attach_diet', + data: {'diet_id': dietId}, + )).called(1); + }); + + test('reattachPersonalDiet - пробрасывает ошибку', () async { + const consultationId = 1; + const dietId = 3; + + when(mockDio.post( + any, + data: anyNamed('data'), + )).thenThrow(DioException( + requestOptions: RequestOptions(path: '/api/chosen_plans/$consultationId/re_attach_diet'), + )); + + expect( + () => service.reattachPersonalDiet(consultationId: consultationId, dietId: dietId), + throwsA(isA()), + ); + }); + }); +} +