import 'package:eatvio_app/core/theme/theme_helper.dart'; import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart'; import 'package:eatvio_app/features/create_plan/repositories/create_plan_repository.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 'basic_widget_test.mocks.dart'; @GenerateMocks([CreatePlanRepository, ProfileRepository, GlossaryRepository]) void main() { group('Meal Plan Creation Basic Widget Tests', () { late MockCreatePlanRepository mockCreatePlanRepository; late CreatePlanCubit createPlanCubit; setUp(() { mockCreatePlanRepository = MockCreatePlanRepository(); createPlanCubit = CreatePlanCubit(createPlanRepository: mockCreatePlanRepository); }); tearDown(() { createPlanCubit.close(); }); Widget createTestWidget(Widget child) { return MaterialApp( theme: ThemeHelper().themeData(), home: BlocProvider( create: (context) => createPlanCubit, child: Scaffold(body: SingleChildScrollView(child: child)), ), ); } testWidgets('should create CreatePlanCubit successfully', (WidgetTester tester) async { // Arrange & Act final cubit = CreatePlanCubit(createPlanRepository: mockCreatePlanRepository); // Assert expect(cubit, isA()); expect(cubit.state.isLoading, isFalse); expect(cubit.state.planCreated, isFalse); cubit.close(); }); testWidgets('should display basic meal plan form fields', (WidgetTester tester) async { // Arrange Widget formWidget = Column( children: [ TextFormField( key: const Key('planNameField'), decoration: const InputDecoration(labelText: 'Название плана питания', hintText: 'Например: План для похудения'), ), const SizedBox(height: 16), TextFormField( key: const Key('planDescriptionField'), decoration: const InputDecoration(labelText: 'Описание плана питания'), maxLines: 3, ), const SizedBox(height: 16), DropdownButtonFormField( key: const Key('planDurationField'), 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), ElevatedButton(key: const Key('publishPlanButton'), onPressed: () {}, child: const Text('Опубликовать план')), ], ); // Act await tester.pumpWidget(createTestWidget(formWidget)); await tester.pumpAndSettle(); // Assert expect(find.byKey(const Key('planNameField')), findsOneWidget); expect(find.byKey(const Key('planDescriptionField')), findsOneWidget); expect(find.byKey(const Key('planDurationField')), findsOneWidget); expect(find.byKey(const Key('publishPlanButton')), findsOneWidget); }); testWidgets('should update plan name when user types in name field', (WidgetTester tester) async { // Arrange Widget formWidget = TextFormField( key: const Key('planNameField'), decoration: const InputDecoration(labelText: 'Название плана питания', hintText: 'Например: План для похудения'), ); await tester.pumpWidget(createTestWidget(formWidget)); await tester.pumpAndSettle(); const testName = 'Тестовый план питания'; // Act await tester.enterText(find.byKey(const Key('planNameField')), testName); await tester.pump(); // Assert expect(find.text(testName), findsOneWidget); }); testWidgets('should update plan description when user types in description field', (WidgetTester tester) async { // Arrange Widget formWidget = TextFormField( key: const Key('planDescriptionField'), decoration: const InputDecoration(labelText: 'Описание плана питания'), maxLines: 3, ); await tester.pumpWidget(createTestWidget(formWidget)); await tester.pumpAndSettle(); const testDescription = 'Это тестовое описание плана питания для здорового образа жизни'; // Act await tester.enterText(find.byKey(const Key('planDescriptionField')), testDescription); await tester.pump(); // Assert expect(find.text(testDescription), findsOneWidget); }); testWidgets('should display plan type selection', (WidgetTester tester) async { // Arrange Widget typeWidget = Column( children: [ const Text('Тип плана питания'), const SizedBox(height: 8), Row( children: [ Expanded( child: CheckboxListTile(key: const Key('slimTypeCheckbox'), title: const Text('Похудение'), value: false, onChanged: (value) {}), ), Expanded( child: CheckboxListTile(key: const Key('fitnessTypeCheckbox'), title: const Text('Фитнес'), value: false, onChanged: (value) {}), ), ], ), Row( children: [ Expanded( child: CheckboxListTile(key: const Key('wellnessTypeCheckbox'), title: const Text('Здоровье'), value: false, onChanged: (value) {}), ), Expanded( child: CheckboxListTile(key: const Key('eatingBehaviorTypeCheckbox'), title: const Text('Поведение'), value: false, onChanged: (value) {}), ), ], ), ], ); // Act await tester.pumpWidget(createTestWidget(typeWidget)); await tester.pumpAndSettle(); // Assert expect(find.text('Тип плана питания'), findsOneWidget); expect(find.byKey(const Key('slimTypeCheckbox')), findsOneWidget); expect(find.byKey(const Key('fitnessTypeCheckbox')), findsOneWidget); expect(find.byKey(const Key('wellnessTypeCheckbox')), findsOneWidget); expect(find.byKey(const Key('eatingBehaviorTypeCheckbox')), findsOneWidget); }); testWidgets('should handle plan type selection', (WidgetTester tester) async { // Arrange bool slimSelected = false; Widget typeWidget = CheckboxListTile( key: const Key('slimTypeCheckbox'), title: const Text('Похудение'), value: slimSelected, onChanged: (value) { slimSelected = value ?? false; }, ); await tester.pumpWidget(createTestWidget(typeWidget)); await tester.pumpAndSettle(); // Act await tester.tap(find.byKey(const Key('slimTypeCheckbox'))); await tester.pump(); // Assert expect(slimSelected, isTrue); }); testWidgets('should display plan duration dropdown', (WidgetTester tester) async { // Arrange Widget durationWidget = DropdownButtonFormField( key: const Key('planDurationField'), decoration: const InputDecoration(labelText: 'Продолжительность плана'), items: const [ DropdownMenuItem(value: 7, child: Text('7 дней')), DropdownMenuItem(value: 14, child: Text('14 дней')), DropdownMenuItem(value: 21, child: Text('21 день')), DropdownMenuItem(value: 30, child: Text('30 дней')), ], onChanged: (value) {}, ); // Act await tester.pumpWidget(createTestWidget(durationWidget)); await tester.pumpAndSettle(); // Assert expect(find.byKey(const Key('planDurationField')), findsOneWidget); expect(find.text('Продолжительность плана'), findsOneWidget); }); testWidgets('should display plan status dropdown', (WidgetTester tester) async { // Arrange Widget statusWidget = DropdownButtonFormField( key: const Key('planStatusField'), decoration: const InputDecoration(labelText: 'Статус плана'), items: const [ DropdownMenuItem(value: 'active', child: Text('Активный')), DropdownMenuItem(value: 'draft', child: Text('Черновик')), DropdownMenuItem(value: 'personal', child: Text('Личный')), ], onChanged: (value) {}, ); // Act await tester.pumpWidget(createTestWidget(statusWidget)); await tester.pumpAndSettle(); // Assert expect(find.byKey(const Key('planStatusField')), findsOneWidget); expect(find.text('Статус плана'), findsOneWidget); }); testWidgets('should display plan options section', (WidgetTester tester) async { // Arrange Widget optionsWidget = Column( children: [ const Text('Опции плана питания'), const SizedBox(height: 16), Container( key: const Key('option1Container'), padding: const EdgeInsets.all(16), decoration: BoxDecoration( border: Border.all(color: Colors.grey), borderRadius: BorderRadius.circular(8), ), child: Column( children: [ TextFormField( key: const Key('option1TitleField'), decoration: const InputDecoration(labelText: 'Название опции', hintText: 'Например: Базовый план'), ), const SizedBox(height: 8), TextFormField( key: const Key('option1PriceField'), decoration: const InputDecoration(labelText: 'Цена', hintText: '1000'), keyboardType: TextInputType.number, ), const SizedBox(height: 8), TextFormField( key: const Key('option1DescriptionField'), decoration: const InputDecoration(labelText: 'Описание опции'), maxLines: 2, ), ], ), ), ], ); // Act await tester.pumpWidget(createTestWidget(optionsWidget)); await tester.pumpAndSettle(); // Assert expect(find.text('Опции плана питания'), findsOneWidget); expect(find.byKey(const Key('option1Container')), findsOneWidget); expect(find.byKey(const Key('option1TitleField')), findsOneWidget); expect(find.byKey(const Key('option1PriceField')), findsOneWidget); expect(find.byKey(const Key('option1DescriptionField')), findsOneWidget); }); testWidgets('should display form labels correctly', (WidgetTester tester) async { // Arrange Widget formWidget = const Column( children: [ Text('Название плана питания'), Text('Описание плана питания'), Text('Продолжительность'), Text('Тип плана питания'), Text('Статус'), Text('Опции плана'), ], ); // Act await tester.pumpWidget(createTestWidget(formWidget)); await tester.pumpAndSettle(); // Assert expect(find.text('Название плана питания'), findsOneWidget); expect(find.text('Описание плана питания'), findsOneWidget); expect(find.text('Продолжительность'), findsOneWidget); expect(find.text('Тип плана питания'), findsOneWidget); expect(find.text('Статус'), findsOneWidget); expect(find.text('Опции плана'), findsOneWidget); }); testWidgets('should display placeholder text in name field', (WidgetTester tester) async { // Arrange Widget formWidget = TextFormField( key: const Key('planNameField'), decoration: const InputDecoration(labelText: 'Название плана питания', hintText: 'Например: План для похудения'), ); // Act await tester.pumpWidget(createTestWidget(formWidget)); await tester.pumpAndSettle(); // Assert expect(find.text('Например: План для похудения'), findsOneWidget); }); testWidgets('should display publish button', (WidgetTester tester) async { // Arrange Widget buttonWidget = ElevatedButton(key: const Key('publishPlanButton'), onPressed: () {}, child: const Text('Опубликовать план')); // Act await tester.pumpWidget(createTestWidget(buttonWidget)); await tester.pumpAndSettle(); // Assert expect(find.byKey(const Key('publishPlanButton')), findsOneWidget); expect(find.text('Опубликовать план'), findsOneWidget); }); testWidgets('should handle publish button tap', (WidgetTester tester) async { // Arrange bool buttonPressed = false; Widget buttonWidget = ElevatedButton( key: const Key('publishPlanButton'), onPressed: () { buttonPressed = true; }, child: const Text('Опубликовать план'), ); await tester.pumpWidget(createTestWidget(buttonWidget)); await tester.pumpAndSettle(); // Act await tester.tap(find.byKey(const Key('publishPlanButton'))); await tester.pump(); // Assert expect(buttonPressed, isTrue); }); testWidgets('should display loading state', (WidgetTester tester) async { // Arrange Widget loadingWidget = const Center(child: CircularProgressIndicator()); // Act await tester.pumpWidget(createTestWidget(loadingWidget)); await tester.pump(); // Assert expect(find.byType(CircularProgressIndicator), findsOneWidget); }); testWidgets('should display error message', (WidgetTester tester) async { // Arrange Widget errorWidget = const Center(child: Text('Произошла ошибка при создании плана питания')); // Act await tester.pumpWidget(createTestWidget(errorWidget)); await tester.pumpAndSettle(); // Assert expect(find.text('Произошла ошибка при создании плана питания'), findsOneWidget); }); testWidgets('should display success message', (WidgetTester tester) async { // Arrange Widget successWidget = const Center(child: Text('План питания успешно создан!')); // Act await tester.pumpWidget(createTestWidget(successWidget)); await tester.pumpAndSettle(); // Assert expect(find.text('План питания успешно создан!'), findsOneWidget); }); testWidgets('should validate required fields', (WidgetTester tester) async { // Arrange Widget validationWidget = Column( children: [ TextFormField( key: const Key('planNameField'), decoration: const InputDecoration(labelText: 'Название плана питания', errorText: 'Название плана питания обязательно'), ), const SizedBox(height: 16), TextFormField( key: const Key('planDescriptionField'), decoration: const InputDecoration(labelText: 'Описание плана питания', errorText: 'Описание плана питания обязательно'), ), ], ); // Act await tester.pumpWidget(createTestWidget(validationWidget)); await tester.pumpAndSettle(); // Assert expect(find.text('Название плана питания обязательно'), findsOneWidget); expect(find.text('Описание плана питания обязательно'), findsOneWidget); }); testWidgets('should display complete meal plan creation form', (WidgetTester tester) async { // Arrange Widget completeForm = Column( children: [ TextFormField( key: const Key('planNameField'), decoration: const InputDecoration(labelText: 'Название плана питания', hintText: 'Например: План для похудения'), ), const SizedBox(height: 16), TextFormField( key: const Key('planDescriptionField'), decoration: const InputDecoration(labelText: 'Описание плана питания'), maxLines: 3, ), const SizedBox(height: 16), DropdownButtonFormField( key: const Key('planDurationField'), 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('planStatusField'), decoration: const InputDecoration(labelText: 'Статус плана'), items: const [ DropdownMenuItem(value: 'active', child: Text('Активный')), DropdownMenuItem(value: 'draft', child: Text('Черновик')), ], onChanged: (value) {}, ), const SizedBox(height: 32), ElevatedButton(key: const Key('publishPlanButton'), onPressed: () {}, child: const Text('Опубликовать план')), ], ); // Act await tester.pumpWidget(createTestWidget(completeForm)); await tester.pumpAndSettle(); // Assert expect(find.byKey(const Key('planNameField')), findsOneWidget); expect(find.byKey(const Key('planDescriptionField')), findsOneWidget); expect(find.byKey(const Key('planDurationField')), findsOneWidget); expect(find.byKey(const Key('planStatusField')), findsOneWidget); expect(find.byKey(const Key('publishPlanButton')), findsOneWidget); }); testWidgets('should display plan type options', (WidgetTester tester) async { // Arrange Widget typeOptionsWidget = const Column( children: [ Text('Выберите тип плана питания:'), SizedBox(height: 8), Text('• Похудение - план для снижения веса'), Text('• Фитнес - план для активного образа жизни'), Text('• Здоровье - план для общего оздоровления'), Text('• Поведение - план для изменения пищевых привычек'), ], ); // Act await tester.pumpWidget(createTestWidget(typeOptionsWidget)); await tester.pumpAndSettle(); // Assert expect(find.text('Выберите тип плана питания:'), findsOneWidget); expect(find.text('• Похудение - план для снижения веса'), findsOneWidget); expect(find.text('• Фитнес - план для активного образа жизни'), findsOneWidget); expect(find.text('• Здоровье - план для общего оздоровления'), findsOneWidget); expect(find.text('• Поведение - план для изменения пищевых привычек'), findsOneWidget); }); testWidgets('should display plan duration options', (WidgetTester tester) async { // Arrange Widget durationOptionsWidget = const Column( children: [ Text('Доступные продолжительности:'), SizedBox(height: 8), Text('• 7 дней - недельный план'), Text('• 14 дней - двухнедельный план'), Text('• 21 день - трехнедельный план'), Text('• 30 дней - месячный план'), ], ); // Act await tester.pumpWidget(createTestWidget(durationOptionsWidget)); await tester.pumpAndSettle(); // Assert expect(find.text('Доступные продолжительности:'), findsOneWidget); expect(find.text('• 7 дней - недельный план'), findsOneWidget); expect(find.text('• 14 дней - двухнедельный план'), findsOneWidget); expect(find.text('• 21 день - трехнедельный план'), findsOneWidget); expect(find.text('• 30 дней - месячный план'), findsOneWidget); }); testWidgets('should display plan options with pricing', (WidgetTester tester) async { // Arrange Widget optionsWidget = Column( children: [ const Text('Настройка опций плана'), const SizedBox(height: 16), Container( key: const Key('basicOptionContainer'), padding: const EdgeInsets.all(16), decoration: BoxDecoration( border: Border.all(color: Colors.blue), borderRadius: BorderRadius.circular(8), ), child: const Column( children: [ Text('Базовая опция', style: TextStyle(fontWeight: FontWeight.bold)), SizedBox(height: 8), Text('Цена: 1000 руб/месяц'), SizedBox(height: 8), Text('Включает: базовое меню, консультации'), ], ), ), const SizedBox(height: 16), Container( key: const Key('premiumOptionContainer'), padding: const EdgeInsets.all(16), decoration: BoxDecoration( border: Border.all(color: Colors.amber), borderRadius: BorderRadius.circular(8), ), child: const Column( children: [ Text('Премиум опция', style: TextStyle(fontWeight: FontWeight.bold)), SizedBox(height: 8), Text('Цена: 2500 руб/месяц'), SizedBox(height: 8), Text('Включает: расширенное меню, персональные консультации'), ], ), ), ], ); // Act await tester.pumpWidget(createTestWidget(optionsWidget)); await tester.pumpAndSettle(); // Assert expect(find.text('Настройка опций плана'), findsOneWidget); expect(find.text('Базовая опция'), findsOneWidget); expect(find.text('Цена: 1000 руб/месяц'), findsOneWidget); expect(find.text('Премиум опция'), findsOneWidget); expect(find.text('Цена: 2500 руб/месяц'), findsOneWidget); expect(find.byKey(const Key('basicOptionContainer')), findsOneWidget); expect(find.byKey(const Key('premiumOptionContainer')), findsOneWidget); }); }); }