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/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_state.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/plans.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/plan_widget.dart'; import 'package:eatvio_app/features/feed/repositories/feed_repository.dart'; import 'package:eatvio_app/features/plans/repositories/plan_repository.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:mockito/annotations.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:network_image_mock/network_image_mock.dart'; import 'package:visibility_detector/visibility_detector.dart'; import 'basic_widget_test.mocks.dart'; @GenerateNiceMocks([MockSpec(), MockSpec()]) void main() { group('Plans Basic Widget Tests', () { late MockFeedRepository mockFeedRepository; late MockPlanRepository mockPlanRepository; late PlansCubit plansCubit; const testPlan = PlanModel( id: 1, slug: 'test-plan', name: 'Test Plan', image: 'test-image.jpg', duration: 30, state: 'active', type: PlanType(fit: true, slim: false, behavior: false, wellness: false), details: 'Test plan description', packetsCount: 1, author: Author(authorSlug: '', authorName: '', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false), totalLikes: 1, totalViews: 1, totalComments: 1, isFavorite: false, minPriceOfOptions: 100.0, maxPriceOfOptions: 500.0, wasLikedByMe: false, ); setUp(() async { await sl.reset(); dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); mockFeedRepository = MockFeedRepository(); mockPlanRepository = MockPlanRepository(); plansCubit = PlansCubit(feedRepository: mockFeedRepository, planRepository: mockPlanRepository); sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); VisibilityDetectorController.instance.updateInterval = Duration.zero; }); tearDown(() async { await Future.delayed(const Duration(milliseconds: 100)); if (!plansCubit.isClosed) { plansCubit.close(); } }); Widget createTestWidget(Widget child, {bool wrapInScaffold = true}) { final widget = BlocProvider( create: (context) => plansCubit, child: Portal( child: wrapInScaffold ? Scaffold(body: SingleChildScrollView(child: child)) : SizedBox(width: 800, height: 1200, child: SingleChildScrollView(child: child)), ), ); return MaterialApp( theme: ThemeHelper().themeData(), localizationsDelegates: const [ S.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [Locale('ru')], home: widget, ); } Widget createPlansTestWidget(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: BlocProvider( create: (context) => plansCubit, child: LayoutBuilder( builder: (context, constraints) => SizedBox( width: constraints.maxWidth > 0 ? constraints.maxWidth : 800, height: constraints.maxHeight > 0 ? constraints.maxHeight : 600, child: child, ), ), ), ), ), ); } testWidgets('should create PlansCubit successfully', (WidgetTester tester) async { // Arrange & Act final cubit = PlansCubit(feedRepository: mockFeedRepository, planRepository: mockPlanRepository); // Assert expect(cubit, isA()); expect(cubit.state.plans, isEmpty); cubit.close(); }); testWidgets('should display PlanWidget with plan name', (WidgetTester tester) async { await mockNetworkImagesFor(() async { // Arrange plansCubit.emit(PlansState.initial().copyWith(plans: [testPlan], isLoading: false)); const widget = PlanWidget(plan: testPlan, index: 0); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.text('Test Plan'), findsOneWidget); expect(find.byType(PlanWidget), findsOneWidget); }); await tester.pump(const Duration(milliseconds: 600)); }); testWidgets('should display PlanWidget with description when details are present', (WidgetTester tester) async { await mockNetworkImagesFor(() async { // Arrange plansCubit.emit(PlansState.initial().copyWith(plans: [testPlan], isLoading: false)); const widget = PlanWidget(plan: testPlan, index: 0); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.text('Test Plan'), findsOneWidget); expect(find.byType(PlanWidget), findsOneWidget); }); await tester.pump(const Duration(milliseconds: 600)); }); testWidgets('should display PlanWidget structure correctly', (WidgetTester tester) async { await mockNetworkImagesFor(() async { // Arrange plansCubit.emit(PlansState.initial().copyWith(plans: [testPlan], isLoading: false)); const widget = PlanWidget(plan: testPlan, index: 0); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.byType(PlanWidget), findsOneWidget); expect(find.text('Test Plan'), findsOneWidget); }); await tester.pump(const Duration(milliseconds: 600)); }); testWidgets('should display Plans widget with loading state', (WidgetTester tester) async { // Arrange plansCubit.emit(PlansState.initial()); final widget = Plans(handleVisibility: ({required visibleFraction, required id, required type}) {}); // Act await tester.pumpWidget(createPlansTestWidget(widget)); await tester.pump(); // Assert expect(find.byType(Plans), findsOneWidget); }); testWidgets('should display Plans widget with loaded state', (WidgetTester tester) async { await mockNetworkImagesFor(() async { // Arrange plansCubit.emit(PlansState.initial().copyWith(plans: [testPlan], isLoading: false)); final widget = Plans(handleVisibility: ({required visibleFraction, required id, required type}) {}); // Act await tester.pumpWidget(createPlansTestWidget(widget)); await tester.pump(); // Assert expect(find.byType(Plans), findsOneWidget); expect(find.byType(RefreshIndicator), findsOneWidget); expect(find.byType(ListView), findsOneWidget); }); await tester.pump(const Duration(milliseconds: 600)); }); testWidgets('should display Plans widget with error state', (WidgetTester tester) async { // Arrange plansCubit.emit(PlansState.initial().copyWith(isLoading: false, errorMessage: 'Error message')); final widget = Plans(handleVisibility: ({required visibleFraction, required id, required type}) {}); // Act await tester.pumpWidget(createPlansTestWidget(widget)); await tester.pump(); // Assert expect(find.byType(Plans), findsOneWidget); }); testWidgets('should display Plans widget with multiple plans', (WidgetTester tester) async { await mockNetworkImagesFor(() async { // Arrange final testPlan2 = testPlan.copyWith(id: 2, name: 'Test Plan 2'); plansCubit.emit(PlansState.initial().copyWith(plans: [testPlan, testPlan2], isLoading: false)); final widget = Plans(handleVisibility: ({required visibleFraction, required id, required type}) {}); // Act await tester.pumpWidget(createPlansTestWidget(widget)); await tester.pump(); // Assert expect(find.byType(Plans), findsOneWidget); expect(find.byType(ListView), findsOneWidget); }); await tester.pump(const Duration(milliseconds: 600)); }); }); }