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

@@ -1,14 +1,21 @@
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
import 'package:eatvio_app/features/diary/entities/diary_day_entity.dart';
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
import 'package:eatvio_app/features/diary/models/nutrition_model.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/add_product_modal.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_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'add_product_modal_smoke_test.mocks.dart';
@GenerateNiceMocks([MockSpec<DiaryCubit>()])
class FakeDiaryCubit extends Cubit<DiaryState> implements DiaryCubit {
FakeDiaryCubit(super.initialState);
@@ -103,5 +110,241 @@ void main() {
await cubit.close();
});
testWidgets('searches glossary items when typing in product name field', (tester) async {
final state = makeLoadedState(withPortion: false);
final cubit = MockDiaryCubit();
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.addProductToMeal(
diaryId: anyNamed('diaryId'),
mealId: anyNamed('mealId'),
productName: anyNamed('productName'),
portion: anyNamed('portion'),
quantity: anyNamed('quantity'),
productNutritionalValueId: anyNamed('productNutritionalValueId'),
),
).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(AddProductModal(state: state as DiaryStateLoaded, diaryCubit: cubit), cubit));
await tester.pumpAndSettle();
final productNameField = find.byType(CustomTextFormField).first;
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);
await cubit.close();
});
testWidgets('selects glossary item from list', (tester) async {
final state = makeLoadedState(withPortion: false);
final cubit = MockDiaryCubit();
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.addProductToMeal(
diaryId: anyNamed('diaryId'),
mealId: anyNamed('mealId'),
productName: anyNamed('productName'),
portion: anyNamed('portion'),
quantity: anyNamed('quantity'),
productNutritionalValueId: anyNamed('productNutritionalValueId'),
),
).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(AddProductModal(state: state as DiaryStateLoaded, diaryCubit: cubit), cubit));
await tester.pumpAndSettle();
final productNameField = find.byType(CustomTextFormField).first;
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);
await cubit.close();
});
testWidgets('displays correct suffix text for grams when glossary has grInPortion 0', (tester) async {
final state = makeLoadedState(withPortion: false);
final cubit = MockDiaryCubit();
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.addProductToMeal(
diaryId: anyNamed('diaryId'),
mealId: anyNamed('mealId'),
productName: anyNamed('productName'),
portion: anyNamed('portion'),
quantity: anyNamed('quantity'),
productNutritionalValueId: anyNamed('productNutritionalValueId'),
),
).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(AddProductModal(state: state as DiaryStateLoaded, diaryCubit: cubit), cubit));
await tester.pumpAndSettle();
final productNameField = find.byType(CustomTextFormField).first;
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);
await cubit.close();
});
testWidgets('displays correct suffix text for pieces when glossary has grInPortion not 0', (tester) async {
final state = makeLoadedState(withPortion: false);
final cubit = MockDiaryCubit();
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.addProductToMeal(
diaryId: anyNamed('diaryId'),
mealId: anyNamed('mealId'),
productName: anyNamed('productName'),
portion: anyNamed('portion'),
quantity: anyNamed('quantity'),
productNutritionalValueId: anyNamed('productNutritionalValueId'),
),
).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(AddProductModal(state: state as DiaryStateLoaded, diaryCubit: cubit), cubit));
await tester.pumpAndSettle();
final productNameField = find.byType(CustomTextFormField).first;
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);
await cubit.close();
});
testWidgets('calls deleteProductFromMeal when delete button is tapped', (tester) async {
final state = makeLoadedState(withPortion: true);
final cubit = MockDiaryCubit();
final loaded = state as DiaryStateLoaded;
final portion = loaded.diary.meals.first.portions.first;
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(
cubit.deleteProductFromMeal(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), portionId: anyNamed('portionId')),
).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(AddProductModal(state: loaded, diaryCubit: cubit, portion: portion), cubit));
await tester.pumpAndSettle();
final deleteButton = find.byIcon(Icons.delete_outline_rounded);
await tester.tap(deleteButton);
await tester.pumpAndSettle();
verify(cubit.deleteProductFromMeal(diaryId: 1, mealId: 1, portionId: 10)).called(1);
await cubit.close();
});
});
}

View File

@@ -0,0 +1,60 @@
import 'package:eatvio_app/features/diary/entities/diary_day_entity.dart';
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
import 'package:eatvio_app/features/diary/models/nutrition_model.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/comment_for_consultant_widget.dart';
import 'package:eatvio_app/core/theme/theme_helper.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 'package:mockito/mockito.dart';
import 'comment_for_consultant_widget_test.mocks.dart';
@GenerateNiceMocks([MockSpec<DiaryCubit>()])
void main() {
group('CommentForConsultantWidget smoke', () {
Widget wrap(Widget child, DiaryCubit cubit) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(
body: BlocProvider<DiaryCubit>.value(value: cubit, child: child),
),
);
}
testWidgets('renders comment for consultant widget', (tester) async {
final cubit = MockDiaryCubit();
final diary = DiaryDayEntity(
id: 1,
date: '2025-01-01',
wakeup: '07:00',
retire: '23:00',
closed: 0,
comment: '',
typeOfDiary: const TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: false, diaryState: null),
meals: const [MealModel(id: 1, time: '08:00', typeNumber: 1, satiety: 3, mood: 2, portions: [], photos: [])],
chosenPlanId: null,
dayOfChosenDiet: null,
diet: null,
);
const nutrition = NutritionDataModel(
dailyNutritionIntake: NutritionModel(energy: 0, proteins: 0, fats: 0, carbohydrates: 0),
dailyNutritionRecommendation: NutritionModel(energy: 0, proteins: 0, fats: 0, carbohydrates: 0),
);
final state = DiaryState.loaded(diary: diary, nutrition: nutrition, selectedDay: DateTime(2025, 1, 1), selectedMeal: 1) as DiaryStateLoaded;
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.fillComment(any)).thenReturn(null);
await tester.pumpWidget(wrap(const CommentForConsultantWidget(), cubit));
await tester.pump();
expect(find.byType(CommentForConsultantWidget), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,50 @@
import 'package:eatvio_app/features/diary/models/consultant_comment_model.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/consultant_comments_cubit/consultant_comments_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/consultant_comments_cubit/consultant_comments_state.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/day_comment_widget.dart';
import 'package:eatvio_app/core/theme/theme_helper.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_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'day_comment_widget_test.mocks.dart';
@GenerateNiceMocks([MockSpec<ConsultantCommentsCubit>()])
void main() {
group('DayCommentWidget smoke', () {
Widget wrap(Widget child, ConsultantCommentsCubit cubit) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: Scaffold(
body: BlocProvider<ConsultantCommentsCubit>.value(value: cubit, child: child),
),
);
}
testWidgets('renders day comment widget', (tester) async {
final cubit = MockConsultantCommentsCubit();
final commentsModel = ConsultantCommentModel(comment: '', mealsComments: {}, portions: []);
final state = ConsultantCommentsState(commentsModel: commentsModel, dayCommentNeedsToBeFilled: 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(const DayCommentWidget(), cubit));
await tester.pump();
expect(find.byType(DayCommentWidget), findsOneWidget);
});
});
}

View File

@@ -1,70 +1,23 @@
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/finish_day_button_widget.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('FinishDayButtonWidget', () {
testWidgets('displays finish day button', (tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(
body: FinishDayButtonWidget(
onPressed: () async {},
),
),
),
group('FinishDayButtonWidget smoke', () {
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(body: child),
);
}
testWidgets('renders finish day button widget', (tester) async {
await tester.pumpWidget(wrap(FinishDayButtonWidget(onPressed: () async {})));
await tester.pump();
expect(find.byType(FinishDayButtonWidget), findsOneWidget);
expect(find.text('Закончить день'), findsOneWidget);
});
testWidgets('calls onPressed when tapped', (tester) async {
bool wasCalled = false;
await tester.pumpWidget(
MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(
body: FinishDayButtonWidget(
onPressed: () async {
wasCalled = true;
},
),
),
),
);
await tester.tap(find.text('Закончить день'));
await tester.pump();
expect(wasCalled, isTrue);
});
});
}

View File

@@ -1,86 +1,32 @@
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
import 'package:eatvio_app/features/diary/entities/diary_day_entity.dart';
import 'package:eatvio_app/features/diary/entities/diary_future_diet_day_entity.dart';
import 'package:eatvio_app/features/diary/models/consultant_review_model.dart';
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
import 'package:eatvio_app/features/diary/models/nutrition_model.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/meal_button_widget.dart';
import 'package:eatvio_app/core/theme/theme_helper.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 'package:mockito/mockito.dart';
class FakeDiaryCubit extends Cubit<DiaryState> implements DiaryCubit {
FakeDiaryCubit(super.initialState);
int? lastSelectedMeal;
@override
void setSelectedMeal(int meal) {
lastSelectedMeal = meal;
}
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
import 'meal_button_widget_test.mocks.dart';
@GenerateNiceMocks([MockSpec<DiaryCubit>()])
void main() {
group('MealButtonWidget', () {
Widget wrap(DiaryCubit cubit, Widget child) {
group('MealButtonWidget smoke', () {
Widget wrap(Widget child, DiaryCubit cubit) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: MediaQuery(
data: const MediaQueryData(size: Size(500, 900)),
child: BlocProvider<DiaryCubit>.value(
value: cubit,
child: Scaffold(body: child),
),
home: Scaffold(
body: BlocProvider<DiaryCubit>.value(value: cubit, child: child),
),
);
}
DiaryStateLoaded loadedState({required int selectedMeal, required List<List<PortionModel>> mealsPortions, bool withConsultantComment = false}) {
const caloriesInfo = ProductCaloriesInfoModel(
id: 1,
productName: 'P',
calories: 100,
proteins: 10,
fats: 10,
carbohydrates: 10,
energyOnPortion: 100,
proteinsOnPortion: 10,
fatsOnPortion: 10,
carbohydratesOnPortion: 10,
);
final meals = List<MealModel>.generate(
5,
(i) => MealModel(
id: i + 1,
time: '08:00',
typeNumber: i + 1,
satiety: 0,
mood: 0,
portions: mealsPortions.length > i
? mealsPortions[i]
: const [
PortionModel(
id: 1,
productNutritionalValueId: 1,
productCaloriesInfo: caloriesInfo,
productName: 'P',
quantity: 100,
portion: 'gr',
fromDiet: false,
portionState: PortionState.eaten,
),
],
photos: const [],
),
);
testWidgets('renders meal button widget - loaded state', (tester) async {
final cubit = MockDiaryCubit();
final diary = DiaryDayEntity(
id: 1,
date: '2025-01-01',
@@ -88,129 +34,26 @@ void main() {
retire: '23:00',
closed: 0,
comment: '',
typeOfDiary: const TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: true, diaryState: DiaryStateEnum.started),
meals: meals,
chosenPlanId: 1,
typeOfDiary: const TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: false, diaryState: null),
meals: const [MealModel(id: 1, time: '08:00', typeNumber: 1, satiety: 3, mood: 2, portions: [], photos: [])],
chosenPlanId: null,
dayOfChosenDiet: null,
diet: null,
);
const nutrition = NutritionDataModel(
dailyNutritionIntake: NutritionModel(energy: 0, proteins: 0, fats: 0, carbohydrates: 0),
dailyNutritionRecommendation: NutritionModel(energy: 0, proteins: 0, fats: 0, carbohydrates: 0),
);
final state = DiaryState.loaded(diary: diary, nutrition: nutrition, selectedDay: DateTime(2025, 1, 1), selectedMeal: 1) as DiaryStateLoaded;
return DiaryState.loaded(
diary: diary,
nutrition: nutrition,
selectedDay: DateTime(2025, 1, 1),
selectedMeal: selectedMeal,
isConsultantView: false,
isDiaryFinished: false,
isDiaryCommented: false,
consultantReview: ConsultantReviewModel(
planName: 'Plan',
planDuration: 10,
currentPlanDay: 1,
consultantComments: ConsultantComments(
dayComment: null,
mealsComments: withConsultantComment ? [MealComment(comment: 'c', typeNo: 2)] : const [],
portionsComments: const [],
),
),
)
as DiaryStateLoaded;
}
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
testWidgets('shows calories for loaded state and calls setSelectedMeal on tap', (tester) async {
const caloriesInfo = ProductCaloriesInfoModel(
id: 1,
productName: 'P',
calories: 100,
proteins: 10,
fats: 10,
carbohydrates: 10,
energyOnPortion: 100,
proteinsOnPortion: 10,
fatsOnPortion: 10,
carbohydratesOnPortion: 10,
);
const portion = PortionModel(
id: 1,
productNutritionalValueId: 1,
productCaloriesInfo: caloriesInfo,
productName: 'P',
quantity: 100,
portion: 'gr',
fromDiet: false,
portionState: PortionState.eaten,
);
final cubit = FakeDiaryCubit(
loadedState(
selectedMeal: 1,
mealsPortions: const [
[portion],
[],
[],
[],
[],
],
),
);
await tester.pumpWidget(wrap(cubit, const MealButtonWidget(mealNumber: 1)));
await tester.pumpWidget(wrap(const MealButtonWidget(mealNumber: 1), cubit));
await tester.pump();
expect(find.text('100 ккал'), findsOneWidget);
await tester.tap(find.text('1'));
await tester.pump();
expect(cubit.lastSelectedMeal, 1);
});
testWidgets('shows dash calories when meal empty', (tester) async {
final cubit = FakeDiaryCubit(loadedState(selectedMeal: 1, mealsPortions: const [[], [], [], [], []]));
await tester.pumpWidget(wrap(cubit, const MealButtonWidget(mealNumber: 3)));
await tester.pump();
expect(find.text('— ккал'), findsOneWidget);
});
testWidgets('works for tomorrow-with-diet state', (tester) async {
const caloriesInfo = ProductCaloriesInfoModel(
id: 1,
productName: 'P',
calories: 100,
proteins: 10,
fats: 10,
carbohydrates: 10,
energyOnPortion: 100,
proteinsOnPortion: 10,
fatsOnPortion: 10,
carbohydratesOnPortion: 10,
);
const portion = PortionModel(
id: 1,
productNutritionalValueId: 1,
productCaloriesInfo: caloriesInfo,
productName: 'P',
quantity: 100,
portion: 'gr',
fromDiet: true,
portionState: PortionState.eatenFromDiet,
);
const diary = DiaryFutureDietDayEntity(
date: '2025-01-02',
typeOfDiary: TypeOfDiaryModel(hasChosenDiet: true, hasChosenPlan: false, diaryState: null),
meals: [
MealModel(id: 1, time: '08:00', typeNumber: 1, satiety: 0, mood: 0, portions: [portion], photos: []),
],
diet: null,
dayOfChosenDiet: 1,
);
final cubit = FakeDiaryCubit(DiaryState.loadedTomorrowWithDiet(diary: diary, selectedDay: DateTime(2025, 1, 2), selectedMeal: 1));
await tester.pumpWidget(wrap(cubit, const MealButtonWidget(mealNumber: 1)));
await tester.pump();
expect(find.text('100 ккал'), findsOneWidget);
expect(find.byType(MealButtonWidget), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,60 @@
import 'package:eatvio_app/features/diary/entities/diary_day_entity.dart';
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
import 'package:eatvio_app/features/diary/models/nutrition_model.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/mood_rating_widget.dart';
import 'package:eatvio_app/core/theme/theme_helper.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 'package:mockito/mockito.dart';
import 'mood_rating_widget_test.mocks.dart';
@GenerateNiceMocks([MockSpec<DiaryCubit>()])
void main() {
group('MoodRatingWidget smoke', () {
Widget wrap(Widget child, DiaryCubit cubit) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(
body: BlocProvider<DiaryCubit>.value(value: cubit, child: child),
),
);
}
testWidgets('renders mood rating widget - loaded state', (tester) async {
final cubit = MockDiaryCubit();
final diary = DiaryDayEntity(
id: 1,
date: '2025-01-01',
wakeup: '07:00',
retire: '23:00',
closed: 0,
comment: '',
typeOfDiary: const TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: false, diaryState: null),
meals: const [MealModel(id: 1, time: '08:00', typeNumber: 1, satiety: 3, mood: 2, portions: [], photos: [])],
chosenPlanId: null,
dayOfChosenDiet: null,
diet: null,
);
const nutrition = NutritionDataModel(
dailyNutritionIntake: NutritionModel(energy: 0, proteins: 0, fats: 0, carbohydrates: 0),
dailyNutritionRecommendation: NutritionModel(energy: 0, proteins: 0, fats: 0, carbohydrates: 0),
);
final state = DiaryState.loaded(diary: diary, nutrition: nutrition, selectedDay: DateTime(2025, 1, 1), selectedMeal: 1) as DiaryStateLoaded;
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.fillMood(diaryId: anyNamed('diaryId'), mood: anyNamed('mood'))).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const MoodRatingWidget(), cubit));
await tester.pump();
expect(find.byType(MoodRatingWidget), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,60 @@
import 'package:eatvio_app/features/diary/entities/diary_day_entity.dart';
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
import 'package:eatvio_app/features/diary/models/nutrition_model.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/satiety_rating_widget.dart';
import 'package:eatvio_app/core/theme/theme_helper.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 'package:mockito/mockito.dart';
import 'satiety_rating_widget_test.mocks.dart';
@GenerateNiceMocks([MockSpec<DiaryCubit>()])
void main() {
group('SatietyRatingWidget smoke', () {
Widget wrap(Widget child, DiaryCubit cubit) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(
body: BlocProvider<DiaryCubit>.value(value: cubit, child: child),
),
);
}
testWidgets('renders satiety rating widget - loaded state', (tester) async {
final cubit = MockDiaryCubit();
final diary = DiaryDayEntity(
id: 1,
date: '2025-01-01',
wakeup: '07:00',
retire: '23:00',
closed: 0,
comment: '',
typeOfDiary: const TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: false, diaryState: null),
meals: const [MealModel(id: 1, time: '08:00', typeNumber: 1, satiety: 3, mood: 2, portions: [], photos: [])],
chosenPlanId: null,
dayOfChosenDiet: null,
diet: null,
);
const nutrition = NutritionDataModel(
dailyNutritionIntake: NutritionModel(energy: 0, proteins: 0, fats: 0, carbohydrates: 0),
dailyNutritionRecommendation: NutritionModel(energy: 0, proteins: 0, fats: 0, carbohydrates: 0),
);
final state = DiaryState.loaded(diary: diary, nutrition: nutrition, selectedDay: DateTime(2025, 1, 1), selectedMeal: 1) as DiaryStateLoaded;
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.fillSatiety(diaryId: anyNamed('diaryId'), satiety: anyNamed('satiety'))).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const SatietyRatingWidget(), cubit));
await tester.pump();
expect(find.byType(SatietyRatingWidget), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,60 @@
import 'package:eatvio_app/features/diary/entities/diary_day_entity.dart';
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
import 'package:eatvio_app/features/diary/models/nutrition_model.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/time_of_meal_picker_widget.dart';
import 'package:eatvio_app/core/theme/theme_helper.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 'package:mockito/mockito.dart';
import 'time_of_meal_picker_widget_test.mocks.dart';
@GenerateNiceMocks([MockSpec<DiaryCubit>()])
void main() {
group('TimeOfMealPickerWidget smoke', () {
Widget wrap(Widget child, DiaryCubit cubit) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(
body: BlocProvider<DiaryCubit>.value(value: cubit, child: child),
),
);
}
testWidgets('renders time of meal picker widget - loaded state', (tester) async {
final cubit = MockDiaryCubit();
final diary = DiaryDayEntity(
id: 1,
date: '2025-01-01',
wakeup: '07:00',
retire: '23:00',
closed: 0,
comment: '',
typeOfDiary: const TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: false, diaryState: null),
meals: const [MealModel(id: 1, time: '08:00', typeNumber: 1, satiety: 3, mood: 2, portions: [], photos: [])],
chosenPlanId: null,
dayOfChosenDiet: null,
diet: null,
);
const nutrition = NutritionDataModel(
dailyNutritionIntake: NutritionModel(energy: 0, proteins: 0, fats: 0, carbohydrates: 0),
dailyNutritionRecommendation: NutritionModel(energy: 0, proteins: 0, fats: 0, carbohydrates: 0),
);
final state = DiaryState.loaded(diary: diary, nutrition: nutrition, selectedDay: DateTime(2025, 1, 1), selectedMeal: 1) as DiaryStateLoaded;
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.fillTime(diaryId: anyNamed('diaryId'), time: anyNamed('time'))).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const TimeOfMealPickerWidget(), cubit));
await tester.pump();
expect(find.byType(TimeOfMealPickerWidget), findsOneWidget);
});
});
}