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/diets/repositories/diet_repository.dart'; import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart'; import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_state.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/diets.dart'; import 'package:eatvio_app/features/feed/presentation/widgets/diets_widget.dart'; import 'package:eatvio_app/features/feed/repositories/feed_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('Diets Basic Widget Tests', () { late MockFeedRepository mockFeedRepository; late MockDietRepository mockDietRepository; late DietsCubit dietsCubit; const testDiet = Diet( id: 1, slug: 'test-diet', name: 'Test Diet', image: 'test-image.jpg', duration: 30, state: DietState.active, type: DietType(light: false, veg: false, carb: false, meat: false), details: 'Test diet description', dailySchedule: {}, author: Author(authorSlug: '', authorName: '', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false), totalLikes: 1, totalViews: 1, totalComments: 1, wasLikedByMe: false, isFavorite: false, dailyNutrition: [], ); setUp(() async { await sl.reset(); dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); mockFeedRepository = MockFeedRepository(); mockDietRepository = MockDietRepository(); dietsCubit = DietsCubit(feedRepository: mockFeedRepository, dietsRepository: mockDietRepository); sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); VisibilityDetectorController.instance.updateInterval = Duration.zero; }); tearDown(() async { await Future.delayed(const Duration(milliseconds: 100)); if (!dietsCubit.isClosed) { dietsCubit.close(); } }); Widget createTestWidget(Widget child, {bool wrapInScaffold = true}) { final widget = BlocProvider( create: (context) => dietsCubit, 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 createDietsTestWidget(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) => dietsCubit, 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 DietsCubit successfully', (WidgetTester tester) async { // Arrange & Act final cubit = DietsCubit(feedRepository: mockFeedRepository, dietsRepository: mockDietRepository); // Assert expect(cubit, isA()); expect(cubit.state.dietsList, isEmpty); cubit.close(); }); testWidgets('should display DietsWidget with diet name', (WidgetTester tester) async { await mockNetworkImagesFor(() async { // Arrange dietsCubit.emit(DietsState.initial().copyWith(dietsList: [testDiet], isLoading: false)); const widget = DietsWidget(diet: testDiet, index: 0); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.text('Test Diet'), findsOneWidget); expect(find.byType(DietsWidget), findsOneWidget); }); await tester.pump(const Duration(milliseconds: 600)); }); testWidgets('should display DietsWidget with description when details are present', (WidgetTester tester) async { await mockNetworkImagesFor(() async { // Arrange dietsCubit.emit(DietsState.initial().copyWith(dietsList: [testDiet], isLoading: false)); const widget = DietsWidget(diet: testDiet, index: 0); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.text('Test Diet'), findsOneWidget); expect(find.byType(DietsWidget), findsOneWidget); }); await tester.pump(const Duration(milliseconds: 600)); }); testWidgets('should display DietsWidget structure correctly', (WidgetTester tester) async { await mockNetworkImagesFor(() async { // Arrange dietsCubit.emit(DietsState.initial().copyWith(dietsList: [testDiet], isLoading: false)); const widget = DietsWidget(diet: testDiet, index: 0); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.byType(DietsWidget), findsOneWidget); expect(find.text('Test Diet'), findsOneWidget); }); await tester.pump(const Duration(milliseconds: 600)); }); testWidgets('should display Diets widget with loading state', (WidgetTester tester) async { // Arrange dietsCubit.emit(DietsState.initial()); final widget = Diets(handleVisibility: ({required visibleFraction, required id, required type}) {}); // Act await tester.pumpWidget(createDietsTestWidget(widget)); await tester.pump(); // Assert expect(find.byType(Diets), findsOneWidget); }); testWidgets('should display Diets widget with loaded state', (WidgetTester tester) async { await mockNetworkImagesFor(() async { // Arrange dietsCubit.emit(DietsState.initial().copyWith(dietsList: [testDiet], isLoading: false)); final widget = Diets(handleVisibility: ({required visibleFraction, required id, required type}) {}); // Act await tester.pumpWidget(createDietsTestWidget(widget)); await tester.pump(); // Assert expect(find.byType(Diets), findsOneWidget); expect(find.byType(RefreshIndicator), findsOneWidget); expect(find.byType(ListView), findsOneWidget); }); await tester.pump(const Duration(milliseconds: 600)); }); testWidgets('should display Diets widget with error state', (WidgetTester tester) async { // Arrange dietsCubit.emit(DietsState.initial().copyWith(isLoading: false, errorMessage: 'Error message')); final widget = Diets(handleVisibility: ({required visibleFraction, required id, required type}) {}); // Act await tester.pumpWidget(createDietsTestWidget(widget)); await tester.pump(); // Assert expect(find.byType(Diets), findsOneWidget); }); testWidgets('should display Diets widget with multiple diets', (WidgetTester tester) async { await mockNetworkImagesFor(() async { // Arrange final testDiet2 = testDiet.copyWith(id: 2, name: 'Test Diet 2'); dietsCubit.emit(DietsState.initial().copyWith(dietsList: [testDiet, testDiet2], isLoading: false)); final widget = Diets(handleVisibility: ({required visibleFraction, required id, required type}) {}); // Act await tester.pumpWidget(createDietsTestWidget(widget)); await tester.pump(); // Assert expect(find.byType(Diets), findsOneWidget); expect(find.byType(ListView), findsOneWidget); }); await tester.pump(const Duration(milliseconds: 600)); }); }); }