feat(tests): increased tests coverage

This commit is contained in:
misha
2025-12-25 12:56:38 +03:00
parent 5b705dfb72
commit 99659f7ea1
132 changed files with 10304 additions and 6226 deletions

View File

@@ -0,0 +1,329 @@
import 'package:eatvio_app/app_keys.dart';
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/create_recipe/entities/recipe_create_entity.dart';
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart';
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_state.dart';
import 'package:eatvio_app/features/create_recipe/presentation/widgets/add_portion_widget.dart';
import 'package:eatvio_app/features/glossary/models/glossary_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'add_portion_widget_test.mocks.dart';
@GenerateNiceMocks([MockSpec<CreateRecipeCubit>()])
void main() {
group('AddPortionWidget smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(body: child),
);
}
testWidgets('renders add portion widget', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: []);
const state = CreateRecipeState(loading: false, entity: entity);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.getGlossaryListByQuery(any)).thenAnswer((_) async => []);
await tester.pumpWidget(
BlocProvider<CreateRecipeCubit>.value(
value: cubit,
child: wrap(AddPortionWidget(createRecipeCubit: cubit)),
),
);
await tester.pumpAndSettle();
expect(find.byType(AddPortionWidget), findsOneWidget);
expect(find.text('Добавление блюда'), findsOneWidget);
expect(find.text('Добавить'), findsOneWidget);
});
testWidgets('renders add portion widget with initial text', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: []);
const state = CreateRecipeState(loading: false, entity: entity);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.getGlossaryListByQuery(any)).thenAnswer((_) async => []);
await tester.pumpWidget(
BlocProvider<CreateRecipeCubit>.value(
value: cubit,
child: wrap(AddPortionWidget(createRecipeCubit: cubit, productNameControllerText: 'Test Product', quantityControllerText: '100')),
),
);
await tester.pumpAndSettle();
expect(find.byType(AddPortionWidget), findsOneWidget);
// Проверяем, что текстовые поля содержат начальные значения через find.text
// Текст может быть не виден сразу, но контроллеры должны быть инициализированы
expect(find.byKey(AppKeys.recipeCreateScreenIngredientNameField), findsOneWidget);
expect(find.byKey(AppKeys.recipeCreateScreenIngredientQuantityField), findsOneWidget);
});
testWidgets('renders edit portion widget with portion index', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: []);
const state = CreateRecipeState(loading: false, entity: entity);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.getGlossaryListByQuery(any)).thenAnswer((_) async => []);
when(cubit.removeIngredient(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<CreateRecipeCubit>.value(
value: cubit,
child: wrap(AddPortionWidget(createRecipeCubit: cubit, portionIndex: 0, productNameControllerText: 'Test Product', quantityControllerText: '100')),
),
);
await tester.pumpAndSettle();
expect(find.byType(AddPortionWidget), findsOneWidget);
expect(find.text('Сохранить'), findsOneWidget);
expect(find.byIcon(Icons.delete_outline_rounded), findsOneWidget);
});
testWidgets('searches glossary items when typing in product name field', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: []);
const state = CreateRecipeState(loading: false, entity: entity);
final testGlossaries = [
const GlossaryModel(
id: 1,
name: 'Test Product 1',
grInPortion: 100,
energyOn100Gr: 100.0,
carbohydratesOn100Gr: 20.0,
proteinsOn100Gr: 10.0,
fatsOn100Gr: 5.0,
energyOnPortion: 100.0,
carbohydratesOnPortion: 20.0,
proteinsOnPortion: 10.0,
fatsOnPortion: 5.0,
),
const GlossaryModel(
id: 2,
name: 'Test Product 2',
grInPortion: 0,
energyOn100Gr: 200.0,
carbohydratesOn100Gr: 30.0,
proteinsOn100Gr: 15.0,
fatsOn100Gr: 10.0,
energyOnPortion: 0.0,
carbohydratesOnPortion: 0.0,
proteinsOnPortion: 0.0,
fatsOnPortion: 0.0,
),
];
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.getGlossaryListByQuery('test')).thenAnswer((_) async => testGlossaries);
when(cubit.addIngredient(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<CreateRecipeCubit>.value(
value: cubit,
child: wrap(AddPortionWidget(createRecipeCubit: cubit)),
),
);
await tester.pumpAndSettle();
final productNameField = find.byKey(AppKeys.recipeCreateScreenIngredientNameField);
await tester.enterText(productNameField, 'test');
await tester.pump(const Duration(milliseconds: 300));
await tester.pumpAndSettle();
expect(find.text('Test Product 1'), findsOneWidget);
expect(find.text('Test Product 2'), findsOneWidget);
});
testWidgets('selects glossary item from list', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: []);
const state = CreateRecipeState(loading: false, entity: entity);
final testGlossaries = [
const GlossaryModel(
id: 1,
name: 'Test Product',
grInPortion: 100,
energyOn100Gr: 100.0,
carbohydratesOn100Gr: 20.0,
proteinsOn100Gr: 10.0,
fatsOn100Gr: 5.0,
energyOnPortion: 100.0,
carbohydratesOnPortion: 20.0,
proteinsOnPortion: 10.0,
fatsOnPortion: 5.0,
),
];
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.getGlossaryListByQuery('test')).thenAnswer((_) async => testGlossaries);
when(cubit.addIngredient(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<CreateRecipeCubit>.value(
value: cubit,
child: wrap(AddPortionWidget(createRecipeCubit: cubit)),
),
);
await tester.pumpAndSettle();
final productNameField = find.byKey(AppKeys.recipeCreateScreenIngredientNameField);
await tester.enterText(productNameField, 'test');
await tester.pump(const Duration(milliseconds: 300));
await tester.pumpAndSettle();
await tester.tap(find.text('Test Product'));
await tester.pumpAndSettle();
expect(find.text('Test Product'), findsOneWidget);
});
testWidgets('displays correct suffix text for grams when glossary has grInPortion 0', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: []);
const state = CreateRecipeState(loading: false, entity: entity);
final testGlossaries = [
const GlossaryModel(
id: 1,
name: 'Test Product',
grInPortion: 0,
energyOn100Gr: 100.0,
carbohydratesOn100Gr: 20.0,
proteinsOn100Gr: 10.0,
fatsOn100Gr: 5.0,
energyOnPortion: 0.0,
carbohydratesOnPortion: 0.0,
proteinsOnPortion: 0.0,
fatsOnPortion: 0.0,
),
];
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.getGlossaryListByQuery('test')).thenAnswer((_) async => testGlossaries);
when(cubit.addIngredient(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<CreateRecipeCubit>.value(
value: cubit,
child: wrap(AddPortionWidget(createRecipeCubit: cubit)),
),
);
await tester.pumpAndSettle();
final productNameField = find.byKey(AppKeys.recipeCreateScreenIngredientNameField);
await tester.enterText(productNameField, 'test');
await tester.pump(const Duration(milliseconds: 300));
await tester.pumpAndSettle();
await tester.tap(find.text('Test Product'));
await tester.pumpAndSettle();
expect(find.text('гр'), findsOneWidget);
});
testWidgets('displays correct suffix text for pieces when glossary has grInPortion not 0', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: []);
const state = CreateRecipeState(loading: false, entity: entity);
final testGlossaries = [
const GlossaryModel(
id: 1,
name: 'Test Product',
grInPortion: 100,
energyOn100Gr: 100.0,
carbohydratesOn100Gr: 20.0,
proteinsOn100Gr: 10.0,
fatsOn100Gr: 5.0,
energyOnPortion: 100.0,
carbohydratesOnPortion: 20.0,
proteinsOnPortion: 10.0,
fatsOnPortion: 5.0,
),
];
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.getGlossaryListByQuery('test')).thenAnswer((_) async => testGlossaries);
when(cubit.addIngredient(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<CreateRecipeCubit>.value(
value: cubit,
child: wrap(AddPortionWidget(createRecipeCubit: cubit)),
),
);
await tester.pumpAndSettle();
final productNameField = find.byKey(AppKeys.recipeCreateScreenIngredientNameField);
await tester.enterText(productNameField, 'test');
await tester.pump(const Duration(milliseconds: 300));
await tester.pumpAndSettle();
await tester.tap(find.text('Test Product'));
await tester.pumpAndSettle();
expect(find.text('шт'), findsOneWidget);
});
testWidgets('calls removeIngredient when delete button is tapped', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: []);
const state = CreateRecipeState(loading: false, entity: entity);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.getGlossaryListByQuery(any)).thenAnswer((_) async => []);
when(cubit.removeIngredient(0)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<CreateRecipeCubit>.value(
value: cubit,
child: wrap(AddPortionWidget(createRecipeCubit: cubit, portionIndex: 0)),
),
);
await tester.pumpAndSettle();
final deleteButton = find.byIcon(Icons.delete_outline_rounded);
await tester.tap(deleteButton);
await tester.pumpAndSettle();
verify(cubit.removeIngredient(0)).called(1);
});
});
}

View File

@@ -0,0 +1,58 @@
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/create_recipe/entities/recipe_create_entity.dart';
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart';
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_state.dart';
import 'package:eatvio_app/features/create_recipe/presentation/widgets/info_about_recipe_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'info_about_recipe_widget_test.mocks.dart';
@GenerateNiceMocks([MockSpec<CreateRecipeCubit>()])
void main() {
group('InfoAboutRecipeWidget smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
tearDown(() async {
await sl.reset();
});
Widget wrap(Widget child, CreateRecipeCubit cubit) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(
body: BlocProvider<CreateRecipeCubit>.value(value: cubit, child: child),
),
);
}
testWidgets('renders info about recipe widget', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(ingredients: [], steps: [], tags: []);
const state = CreateRecipeState(entity: entity, loading: false);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(InfoAboutRecipeWidget(createRecipeCubit: cubit), cubit));
await tester.pump();
expect(find.byType(InfoAboutRecipeWidget), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,56 @@
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/create_recipe/entities/recipe_create_entity.dart';
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart';
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_state.dart';
import 'package:eatvio_app/features/create_recipe/presentation/widgets/portion_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'portion_widget_test.mocks.dart';
@GenerateNiceMocks([MockSpec<CreateRecipeCubit>()])
void main() {
group('PortionWidget smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(body: child),
);
}
testWidgets('renders portion widget', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: []);
const state = CreateRecipeState(loading: false, entity: entity);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.replacePortionsCount(any)).thenReturn(null);
when(cubit.replaceEnegryInPortion(any)).thenReturn(null);
when(cubit.validateServings()).thenReturn(true);
when(cubit.validateEnergyPerServing()).thenReturn(true);
await tester.pumpWidget(BlocProvider<CreateRecipeCubit>.value(value: cubit, child: wrap(const PortionWidget())));
await tester.pumpAndSettle();
expect(find.byType(PortionWidget), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,59 @@
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/create_recipe/entities/recipe_create_entity.dart';
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart';
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_state.dart';
import 'package:eatvio_app/features/create_recipe/presentation/widgets/steps_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'steps_widget_test.mocks.dart';
@GenerateNiceMocks([MockSpec<CreateRecipeCubit>()])
void main() {
group('StepsWidget smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(body: child),
);
}
testWidgets('renders steps widget', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: []);
const state = CreateRecipeState(loading: false, entity: entity);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.addStep()).thenReturn(null);
when(cubit.removeStep(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<CreateRecipeCubit>.value(
value: cubit,
child: wrap(StepsWidget(createRecipeCubit: cubit)),
),
);
await tester.pumpAndSettle();
expect(find.byType(StepsWidget), findsOneWidget);
});
});
}

View File

@@ -1,3 +1,6 @@
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/create_recipe/entities/recipe_create_entity.dart';
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart';
@@ -5,109 +8,66 @@ import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recip
import 'package:eatvio_app/features/create_recipe/presentation/widgets/tags_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'tags_widget_test.mocks.dart';
@GenerateMocks([CreateRecipeCubit])
@GenerateNiceMocks([MockSpec<CreateRecipeCubit>()])
void main() {
group('TagsWidget', () {
late MockCreateRecipeCubit mockCubit;
setUp(() {
mockCubit = MockCreateRecipeCubit();
group('TagsWidget smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
Widget createTestWidget() {
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: BlocProvider<CreateRecipeCubit>.value(
value: mockCubit,
child: const Scaffold(
body: TagsWidget(),
),
),
home: Scaffold(body: child),
);
}
testWidgets('displays tags widget', (tester) async {
const initialState = CreateRecipeState(
entity: RecipeCreateEntity(
ingredients: [],
steps: [],
tags: [],
),
loading: false,
);
when(mockCubit.state).thenReturn(initialState);
when(mockCubit.stream).thenAnswer((_) => Stream.value(initialState));
// ignore: return_of_invalid_type
when(mockCubit.addTag(any)).thenAnswer((_) => () {});
// ignore: return_of_invalid_type
when(mockCubit.removeTag(any)).thenAnswer((_) => () {});
testWidgets('renders tags widget', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: []);
const state = CreateRecipeState(loading: false, entity: entity);
await tester.pumpWidget(createTestWidget());
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.addTag(any)).thenReturn(null);
when(cubit.removeTag(any)).thenReturn(null);
await tester.pumpWidget(BlocProvider<CreateRecipeCubit>.value(value: cubit, child: wrap(const TagsWidget())));
await tester.pumpAndSettle();
expect(find.byType(TagsWidget), findsOneWidget);
});
testWidgets('displays existing tags', (tester) async {
const stateWithTags = CreateRecipeState(
entity: RecipeCreateEntity(
ingredients: [],
steps: [],
tags: ['tag1', 'tag2'],
),
loading: false,
);
when(mockCubit.state).thenReturn(stateWithTags);
when(mockCubit.stream).thenAnswer((_) => Stream.value(stateWithTags));
// ignore: return_of_invalid_type
when(mockCubit.addTag(any)).thenAnswer((_) => () {});
// ignore: return_of_invalid_type
when(mockCubit.removeTag(any)).thenAnswer((_) => () {});
testWidgets('renders tags widget with tags', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: ['tag1', 'tag2']);
const state = CreateRecipeState(loading: false, entity: entity);
await tester.pumpWidget(createTestWidget());
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.addTag(any)).thenReturn(null);
when(cubit.removeTag(any)).thenReturn(null);
await tester.pumpWidget(BlocProvider<CreateRecipeCubit>.value(value: cubit, child: wrap(const TagsWidget())));
await tester.pumpAndSettle();
expect(find.byType(TagsWidget), findsOneWidget);
expect(find.text('tag1'), findsOneWidget);
expect(find.text('tag2'), findsOneWidget);
});
testWidgets('calls addTag when add button is tapped', (tester) async {
const initialState = CreateRecipeState(
entity: RecipeCreateEntity(
ingredients: [],
steps: [],
tags: [],
),
loading: false,
);
when(mockCubit.state).thenReturn(initialState);
when(mockCubit.stream).thenAnswer((_) => Stream.value(initialState));
// ignore: return_of_invalid_type
when(mockCubit.addTag(any)).thenAnswer((_) => () {});
// ignore: return_of_invalid_type
when(mockCubit.removeTag(any)).thenAnswer((_) => () {});
await tester.pumpWidget(createTestWidget());
await tester.pumpAndSettle();
// Find text field and enter tag
final textField = find.byType(TextField);
await tester.enterText(textField, 'new tag');
await tester.pump();
// Find and tap add button
final addButton = find.byIcon(Icons.done);
await tester.tap(addButton);
await tester.pump();
verify(mockCubit.addTag('new tag')).called(1);
});
});
}

View File

@@ -0,0 +1,58 @@
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/create_recipe/entities/recipe_create_entity.dart';
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart';
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_state.dart';
import 'package:eatvio_app/features/create_recipe/presentation/widgets/time_of_cook_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'time_of_cook_widget_test.mocks.dart';
@GenerateNiceMocks([MockSpec<CreateRecipeCubit>()])
void main() {
group('TimeOfCookWidget smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(body: child),
);
}
testWidgets('renders time of cook widget', (tester) async {
final cubit = MockCreateRecipeCubit();
const entity = RecipeCreateEntity(typeOfRecipe: TypeOfRecipe.firstMeals, ingredients: [], steps: [StepEntity()], tags: []);
const state = CreateRecipeState(loading: false, entity: entity);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.setTotalCookingHours(any)).thenReturn(null);
when(cubit.setTotalCookingMinutes(any)).thenReturn(null);
when(cubit.setActiveCookingHours(any)).thenReturn(null);
when(cubit.setActiveCookingMinutes(any)).thenReturn(null);
when(cubit.validateTotalCookTime()).thenReturn(true);
when(cubit.validateActiveCookTime()).thenReturn(true);
await tester.pumpWidget(BlocProvider<CreateRecipeCubit>.value(value: cubit, child: wrap(const TimeOfCookWidget())));
await tester.pumpAndSettle();
expect(find.byType(TimeOfCookWidget), findsOneWidget);
});
});
}