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/animated_option_button.dart'; import 'package:eatvio_app/core/widgets/custom_outlined_button.dart'; import 'package:eatvio_app/features/feed/models/recipes_model.dart' as recipes; import 'package:eatvio_app/features/recipe/models/my_recipe_model.dart'; import 'package:eatvio_app/features/recipe/presentation/cubit/my_recipes_cubit/my_recieps_cubit.dart'; import 'package:eatvio_app/features/recipe/presentation/cubit/my_recipes_cubit/my_recipes_state.dart'; import 'package:eatvio_app/features/recipe/presentation/widgets/my_recipe_widget.dart'; import 'package:eatvio_app/features/recipe/presentation/widgets/my_recipes_tab.dart'; import 'package:eatvio_app/features/recipe/repositories/about_recipe_repository.dart'; import 'package:eatvio_app/features/recipe/repositories/my_recipes_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 'basic_widget_test.mocks.dart'; @GenerateNiceMocks([MockSpec(), MockSpec()]) void main() { group('MyRecipes Basic Widget Tests', () { late MockMyRecipesRepository mockMyRecipesRepository; late MockAboutRecipeRepository mockAboutRecipeRepository; late MyRecipesCubit myRecipesCubit; const testRecipe = MyRecipeModel( id: 1, image: 'test-image.jpg', state: 'active', cookingTime: 30, activeCookingTime: 20, description: 'Test recipe description', steps: [ recipes.Step(image: 'https://someurl.com/step1.jpg', description: 'Step 1 description'), recipes.Step(image: 'https://someurl.com/step2.jpg', description: 'Step 2 description'), ], videoUrl: 'https://someurl.com/video.mp4', title: 'Test Recipe', slug: 'test-recipe', calories: 250.0, likesCount: 5, viewsCount: 10, ); setUp(() async { await sl.reset(); dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost'); mockMyRecipesRepository = MockMyRecipesRepository(); mockAboutRecipeRepository = MockAboutRecipeRepository(); myRecipesCubit = MyRecipesCubit(myRecipesRepository: mockMyRecipesRepository, aboutRecipeRepository: mockAboutRecipeRepository); sl.registerLazySingleton(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost')); }); tearDown(() async { await Future.delayed(const Duration(milliseconds: 100)); if (!myRecipesCubit.isClosed) { myRecipesCubit.close(); } }); Widget createTestWidget(Widget child, {bool wrapInScaffold = true}) { final widget = BlocProvider( create: (context) => myRecipesCubit, child: Portal( child: wrapInScaffold ? Scaffold(body: SingleChildScrollView(child: child)) : SizedBox(width: 800, height: 600, child: child), ), ); return MaterialApp( theme: ThemeHelper().themeData(), localizationsDelegates: const [ S.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [Locale('ru')], home: widget, ); } testWidgets('should create MyRecipesCubit successfully', (WidgetTester tester) async { // Arrange & Act final cubit = MyRecipesCubit(myRecipesRepository: mockMyRecipesRepository, aboutRecipeRepository: mockAboutRecipeRepository); // Assert expect(cubit, isA()); expect(cubit.state, isA()); cubit.close(); }); testWidgets('should display MyRecipesTab with all tabs', (WidgetTester tester) async { // Arrange const widget = MyRecipesTab(); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pumpAndSettle(); // Assert expect(find.byType(MyRecipesTab), findsOneWidget); expect(find.byType(AnimatedOptionButton), findsNWidgets(2)); }); testWidgets('should handle tab selection in MyRecipesTab', (WidgetTester tester) async { // Arrange bool callbackCalled = false; final widget = MyRecipesTab( additionalOnTap: () { callbackCalled = true; }, ); await tester.pumpWidget(createTestWidget(widget)); await tester.pumpAndSettle(); // Act final tabButtons = find.byType(AnimatedOptionButton); expect(tabButtons, findsNWidgets(2)); await tester.tap(tabButtons.at(0)); await tester.pump(); // Assert expect(callbackCalled, true); }); testWidgets('should display MyRecipeWidget with recipe title', (WidgetTester tester) async { // Arrange myRecipesCubit.emit(const MyRecipesState.loaded(recipes: [testRecipe], selectedState: 'active')); const widget = MyRecipeWidget(recipe: testRecipe); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.text('Test Recipe'), findsOneWidget); expect(find.byType(MyRecipeWidget), findsOneWidget); }); testWidgets('should display MyRecipeWidget with description when description is present', (WidgetTester tester) async { // Arrange myRecipesCubit.emit(const MyRecipesState.loaded(recipes: [testRecipe], selectedState: 'active')); const widget = MyRecipeWidget(recipe: testRecipe); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.text('Test Recipe'), findsOneWidget); expect(find.byType(MyRecipeWidget), findsOneWidget); }); testWidgets('should display MyRecipeWidget buttons', (WidgetTester tester) async { // Arrange myRecipesCubit.emit(const MyRecipesState.loaded(recipes: [testRecipe], selectedState: 'active')); const widget = MyRecipeWidget(recipe: testRecipe); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.byType(MyRecipeWidget), findsOneWidget); expect(find.byType(CustomOutlinedButton), findsWidgets); }); testWidgets('should display MyRecipeWidget with cooking time', (WidgetTester tester) async { // Arrange myRecipesCubit.emit(const MyRecipesState.loaded(recipes: [testRecipe], selectedState: 'active')); const widget = MyRecipeWidget(recipe: testRecipe); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.byType(MyRecipeWidget), findsOneWidget); expect(find.text('Test Recipe'), findsOneWidget); }); testWidgets('should display MyRecipeWidget with steps count', (WidgetTester tester) async { // Arrange myRecipesCubit.emit(const MyRecipesState.loaded(recipes: [testRecipe], selectedState: 'active')); const widget = MyRecipeWidget(recipe: testRecipe); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.byType(MyRecipeWidget), findsOneWidget); expect(find.text('Test Recipe'), findsOneWidget); }); testWidgets('should display MyRecipeWidget with calories', (WidgetTester tester) async { // Arrange myRecipesCubit.emit(const MyRecipesState.loaded(recipes: [testRecipe], selectedState: 'active')); const widget = MyRecipeWidget(recipe: testRecipe); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.byType(MyRecipeWidget), findsOneWidget); expect(find.text('Test Recipe'), findsOneWidget); }); testWidgets('should display MyRecipeWidget with null steps', (WidgetTester tester) async { // Arrange myRecipesCubit.emit(const MyRecipesState.loaded(recipes: [testRecipe], selectedState: 'active')); final recipeWithoutSteps = testRecipe.copyWith(steps: null); final widget = MyRecipeWidget(recipe: recipeWithoutSteps); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.byType(MyRecipeWidget), findsOneWidget); expect(find.text('Test Recipe'), findsOneWidget); }); testWidgets('should display MyRecipeWidget structure correctly', (WidgetTester tester) async { // Arrange myRecipesCubit.emit(const MyRecipesState.loaded(recipes: [testRecipe], selectedState: 'active')); const widget = MyRecipeWidget(recipe: testRecipe); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100)); // Assert expect(find.byType(MyRecipeWidget), findsOneWidget); expect(find.text('Test Recipe'), findsOneWidget); expect(find.byType(CustomOutlinedButton), findsWidgets); }); testWidgets('should display MyRecipesTab structure correctly', (WidgetTester tester) async { // Arrange const widget = MyRecipesTab(); // Act await tester.pumpWidget(createTestWidget(widget)); await tester.pumpAndSettle(); // Assert expect(find.byType(MyRecipesTab), findsOneWidget); expect(find.byType(AnimatedOptionButton), findsNWidgets(2)); }); }); }