import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:eatvio_app/core/locator_service.dart'; import 'package:eatvio_app/core/app_config.dart'; import 'package:eatvio_app/core/app_initializer.dart'; import 'package:eatvio_app/features/create_diet/presentation/widgets/diet_duration_drop_down_widget.dart'; import 'package:eatvio_app/features/create_diet/presentation/widgets/status_drop_down_widget.dart'; import 'package:eatvio_app/features/create_diet/presentation/widgets/diet_type_choice_widget.dart'; import 'package:eatvio_app/features/create_diet/presentation/widgets/diet_image_picker_widget.dart'; import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:eatvio_app/generated/l10n.dart'; import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart'; import 'package:eatvio_app/features/create_diet/presentation/create_diet_screen.dart'; import 'package:eatvio_app/features/create_diet/repositories/create_diet_repository.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/glossary/repositories/glossary_repository.dart'; import 'package:eatvio_app/features/profile/repositories/profile_repository.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'integration_widget_test.mocks.dart'; @GenerateMocks([CreateDietRepository, ProfileRepository, GlossaryRepository]) void main() { group('Diet Creation Integration Widget Tests', () { late MockCreateDietRepository mockCreateDietRepository; late MockProfileRepository mockProfileRepository; late MockGlossaryRepository mockGlossaryRepository; late CreateDietCubit createDietCubit; setUp(() async { await sl.reset(); // Ensure dotenv has required keys before AppConfig constructor reads them dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); // Register minimal AppConfig for tests to satisfy dependencies (e.g. image URL building) sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); mockCreateDietRepository = MockCreateDietRepository(); mockProfileRepository = MockProfileRepository(); mockGlossaryRepository = MockGlossaryRepository(); createDietCubit = CreateDietCubit( createDietRepository: mockCreateDietRepository, profileRepository: mockProfileRepository, glossaryRepository: mockGlossaryRepository, ); sl.registerLazySingleton(() => createDietCubit); when(mockCreateDietRepository.getDietPortionsNutrition(any)).thenAnswer((_) async => >>{}); }); tearDown(() { createDietCubit.close(); }); Widget createTestWidget() { return MaterialApp( theme: ThemeHelper().themeData(), localizationsDelegates: const [ S.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [Locale('ru')], home: BlocProvider(create: (context) => createDietCubit, child: const CreateDietScreen()), ); } testWidgets('should display CreateDietScreen', (WidgetTester tester) async { // Arrange & Act await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); // Assert expect(find.byType(CreateDietScreen), findsOneWidget); }); testWidgets('should display diet creation form elements', (WidgetTester tester) async { // Arrange final arranged = Scaffold( appBar: AppBar(title: const Text('Создание диеты')), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ TextFormField( key: const Key('dietNameField'), decoration: const InputDecoration(labelText: 'Название диеты', hintText: 'Введите название диеты'), ), const SizedBox(height: 16), TextFormField( key: const Key('dietDescriptionField'), decoration: const InputDecoration(labelText: 'Описание диеты', hintText: 'Опишите особенности диеты'), maxLines: 3, ), const SizedBox(height: 16), DropdownButtonFormField( key: const Key('dietDurationField'), decoration: const InputDecoration(labelText: 'Продолжительность'), items: const [ DropdownMenuItem(value: 7, child: Text('7 дней')), DropdownMenuItem(value: 14, child: Text('14 дней')), DropdownMenuItem(value: 21, child: Text('21 день')), ], onChanged: (value) {}, ), const SizedBox(height: 16), DropdownButtonFormField( key: const Key('dietStatusField'), decoration: const InputDecoration(labelText: 'Статус диеты'), items: const [ DropdownMenuItem(value: 'active', child: Text('Активная')), DropdownMenuItem(value: 'draft', child: Text('Черновик')), ], onChanged: (value) {}, ), const SizedBox(height: 32), SizedBox( width: double.infinity, child: ElevatedButton(key: const Key('createDietButton'), onPressed: () {}, child: const Text('Создать диету')), ), ], ), ), ), ); // Act await tester.pumpWidget(MaterialApp(theme: ThemeHelper().themeData(), home: arranged)); await tester.pumpAndSettle(); // Assert expect(find.text('Создание диеты'), findsOneWidget); }); testWidgets('should handle diet creation workflow', (WidgetTester tester) async { // Arrange final arranged = Column( children: [ TextFormField( key: const Key('dietNameField'), decoration: const InputDecoration(labelText: 'Название диеты'), ), const SizedBox(height: 16), TextFormField( key: const Key('dietDescriptionField'), decoration: const InputDecoration(labelText: 'Описание диеты'), ), const SizedBox(height: 16), ElevatedButton(key: const Key('createDietButton'), onPressed: () {}, child: const Text('Создать диету')), ], ); await tester.pumpWidget( MaterialApp( theme: ThemeHelper().themeData(), home: Scaffold(body: SingleChildScrollView(child: arranged)), ), ); await tester.pumpAndSettle(); // Act - Fill in diet information await tester.enterText(find.byKey(const Key('dietNameField')), 'Тестовая диета'); await tester.enterText(find.byKey(const Key('dietDescriptionField')), 'Описание тестовой диеты'); await tester.pump(); // Assert expect(find.text('Тестовая диета'), findsOneWidget); expect(find.text('Описание тестовой диеты'), findsOneWidget); }); testWidgets('should validate diet creation form', (WidgetTester tester) async { // Arrange final arranged = Column( children: [ TextFormField( key: const Key('dietNameField'), decoration: const InputDecoration(labelText: 'Название диеты', errorText: 'Название диеты обязательно'), ), const SizedBox(height: 16), TextFormField( key: const Key('dietDescriptionField'), decoration: const InputDecoration(labelText: 'Описание диеты', errorText: 'Описание диеты обязательно'), ), const SizedBox(height: 16), ElevatedButton(key: const Key('createDietButton'), onPressed: () {}, child: const Text('Создать диету')), ], ); // Act await tester.pumpWidget( MaterialApp( theme: ThemeHelper().themeData(), home: Scaffold(body: arranged), ), ); await tester.pumpAndSettle(); // Assert expect(find.text('Название диеты обязательно'), findsOneWidget); expect(find.text('Описание диеты обязательно'), findsOneWidget); }); testWidgets('should display diet creation success state', (WidgetTester tester) async { // Arrange const arranged = Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.check_circle, size: 64, color: Colors.green), SizedBox(height: 16), Text('Диета успешно создана!', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), SizedBox(height: 8), Text('Ваша диета была сохранена и готова к использованию.'), ], ), ); // Act await tester.pumpWidget(MaterialApp(theme: ThemeHelper().themeData(), home: arranged)); await tester.pumpAndSettle(); // Assert expect(find.text('Диета успешно создана!'), findsOneWidget); expect(find.text('Ваша диета была сохранена и готова к использованию.'), findsOneWidget); }); testWidgets('should display diet creation error state', (WidgetTester tester) async { // Arrange const arranged = Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.error, size: 64, color: Colors.red), SizedBox(height: 16), Text('Ошибка создания диеты', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), SizedBox(height: 8), Text('Произошла ошибка при создании диеты. Попробуйте еще раз.'), ], ), ); // Act await tester.pumpWidget(MaterialApp(theme: ThemeHelper().themeData(), home: arranged)); await tester.pumpAndSettle(); // Assert expect(find.text('Ошибка создания диеты'), findsOneWidget); expect(find.text('Произошла ошибка при создании диеты. Попробуйте еще раз.'), findsOneWidget); }); testWidgets('should display diet creation loading state', (WidgetTester tester) async { // Arrange const arranged = Center( child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [CircularProgressIndicator(), SizedBox(height: 16), Text('Создание диеты...')]), ); // Act await tester.pumpWidget(MaterialApp(theme: ThemeHelper().themeData(), home: arranged)); await tester.pump(); // Assert expect(find.byType(CircularProgressIndicator), findsOneWidget); expect(find.text('Создание диеты...'), findsOneWidget); }); testWidgets('should handle diet editing workflow', (WidgetTester tester) async { // Arrange const testDiet = Diet( id: 1, slug: 'test-diet', name: 'Тестовая диета', image: 'base64image', duration: 7, state: DietState.active, type: DietType(meat: true, veg: false, carb: true, light: false), details: 'Описание тестовой диеты', dailySchedule: {}, author: Author(authorSlug: 'test-author', authorName: 'Test Author', authorProfileIcon: '', authorIsMe: true, isEntitySubscribedByMe: false), totalLikes: 0, totalViews: 0, totalComments: 0, wasLikedByMe: false, isFavorite: false, dailyNutrition: [], ); Widget editWidget = MaterialApp( theme: ThemeHelper().themeData(), localizationsDelegates: const [ S.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [Locale('ru')], home: BlocProvider( create: (context) => createDietCubit, child: const CreateDietScreen(diet: testDiet), ), ); // Act await tester.pumpWidget(editWidget); await tester.pumpAndSettle(); // Assert expect(find.byType(CreateDietScreen), findsOneWidget); }); testWidgets('should display diet creation form with all required fields', (WidgetTester tester) async { // Act await tester.pumpWidget(createTestWidget()); await tester.pumpAndSettle(); // Assert // Title expect(find.text('Создание диеты'), findsOneWidget); // Core widgets present on real screen expect(find.byType(DietDurationDropDownWidget), findsOneWidget); expect(find.byType(StatusDropDownWidget), findsOneWidget); expect(find.byType(DietTypeChoiceWidget), findsOneWidget); expect(find.byType(DietImagePickerWidget), findsOneWidget); // Action buttons expect(find.byType(CustomOutlinedButton), findsNWidgets(2)); }); }); }