Files
eatvio_app/test/features/diary/presentation/bloc/diary_cubit_test.dart
2026-01-26 16:38:15 +03:00

1081 lines
46 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:dio/dio.dart';
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
import 'package:eatvio_app/features/diary/entities/diary_future_diet_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/repositories/diary_repository.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/glossary/models/glossary_model.dart';
import 'package:eatvio_app/features/glossary/repositories/glossary_repository.dart';
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
import 'package:eatvio_app/features/settings/models/profile_settings_model.dart';
import 'package:eatvio_app/features/settings/repositories/service_repository.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'diary_cubit_test.mocks.dart';
@GenerateNiceMocks([
MockSpec<DiaryRepository>(),
MockSpec<GlossaryRepository>(),
MockSpec<ProfileRepository>(),
MockSpec<DietRepository>(),
MockSpec<ChatRepository>(),
MockSpec<SettingsRepository>(),
])
void main() {
group('DiaryCubit', () {
DiaryCubit? diaryCubit;
late MockDiaryRepository mockDiaryRepository;
late MockGlossaryRepository mockGlossaryRepository;
late MockProfileRepository mockProfileRepository;
late MockDietRepository mockDietRepository;
late MockChatRepository mockChatRepository;
late MockSettingsRepository mockSettingsRepository;
const testDiaryDay = DiaryDayModel(
id: 1,
date: '2024-01-15',
closed: 0,
comment: '',
typeOfDiary: TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: false, diaryState: null),
meals: [],
chosenPlanId: null,
dayOfChosenDiet: null,
diet: null,
);
const testNutrition = NutritionDataModel(
dailyNutritionIntake: NutritionModel(energy: 2000.0, proteins: 150.0, fats: 80.0, carbohydrates: 250.0),
dailyNutritionRecommendation: NutritionModel(energy: 2200.0, proteins: 160.0, fats: 90.0, carbohydrates: 270.0),
);
setUp(() {
mockDiaryRepository = MockDiaryRepository();
mockGlossaryRepository = MockGlossaryRepository();
mockProfileRepository = MockProfileRepository();
mockDietRepository = MockDietRepository();
mockChatRepository = MockChatRepository();
mockSettingsRepository = MockSettingsRepository();
});
tearDown(() async {
if (diaryCubit != null && !diaryCubit!.isClosed) {
await Future.delayed(const Duration(milliseconds: 100));
diaryCubit!.close();
diaryCubit = null;
}
});
test('начальное состояние - loading', () {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
expect(diaryCubit!.state, const DiaryState.loading());
});
test('setSelectedDay - успешно меняет выбранный день', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
final result = await diaryCubit!.setSelectedDay(DateTime(2024, 1, 15));
expect(result, true);
await Future.delayed(const Duration(milliseconds: 100));
expect(diaryCubit!.state, isA<DiaryStateLoaded>());
});
test('fetchDiaryV2 - загружает дневник по ID', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.getDiaryDay(any)).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
final result = await diaryCubit!.fetchDiaryV2(needLoading: true, diaryId: 1);
expect(result, true);
await Future.delayed(const Duration(milliseconds: 100));
expect(diaryCubit!.state, isA<DiaryStateLoaded>());
});
test('fetchDiaryV2 - обрабатывает ошибку 422 при создании дня', () async {
when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenThrow(
DioException(
requestOptions: RequestOptions(path: ''),
response: Response(requestOptions: RequestOptions(path: ''), statusCode: 422),
),
);
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
final result = await diaryCubit!.fetchDiaryV2(needLoading: true);
expect(result, true);
await Future.delayed(const Duration(milliseconds: 100));
expect(diaryCubit!.state, isA<DiaryStateLoaded>());
});
test('setSelectedMeal - меняет выбранный прием пищи', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
diaryCubit!.setSelectedMeal(2);
expect(diaryCubit!.selectedMeal, 2);
expect(diaryCubit!.state, isA<DiaryStateLoaded>());
});
test('setDiaryForDietOnly - устанавливает дневник только для диеты', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
const diet = Diet(
id: 1,
slug: 'test-diet',
name: 'Test Diet',
image: '',
duration: 7,
state: DietState.active,
type: DietType(),
details: '',
dailySchedule: {
1: {
1: {1: DailySchedule(name: 'Яблоко', portion: Portion.grams, quantity: 1)},
},
},
author: Author(authorSlug: 'test', authorName: 'Test', authorProfileIcon: '', authorIsMe: false),
totalLikes: 0,
totalViews: 0,
totalComments: 0,
wasLikedByMe: false,
isFavorite: false,
dailyNutrition: [],
);
when(mockDietRepository.getDiet(1)).thenAnswer((_) async => diet);
final result = await diaryCubit!.setDiaryForDietOnly(
const DiaryFutureDietDayEntity(
date: '2024-01-15',
typeOfDiary: TypeOfDiaryModel(hasChosenDiet: true, hasChosenPlan: false, diaryState: null),
meals: [],
dayOfChosenDiet: 1,
diet: DiaryDietModel(id: 1, duration: 7, name: 'Test Diet'),
),
);
expect(result, true);
expect(diaryCubit!.state, isA<DiaryStateLoadedTomorrowWithDiet>());
});
test('setDiaryForDietOnly - возвращает false если нет выбранной диеты', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
final result = await diaryCubit!.setDiaryForDietOnly(
const DiaryFutureDietDayEntity(
date: '2024-01-15',
typeOfDiary: TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: false, diaryState: null),
meals: [],
dayOfChosenDiet: null,
diet: null,
),
);
expect(result, false);
});
test('finishDiaryDay - завершает день дневника', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(
mockDiaryRepository.finishDiaryDay(diaryId: anyNamed('diaryId'), wakeUp: anyNamed('wakeUp'), retire: anyNamed('retire'), comment: anyNamed('comment')),
).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.finishDiaryDay(diaryId: 1, wakeUp: '07:00', retire: '23:00');
await Future.delayed(const Duration(milliseconds: 100));
});
test('addProductToMeal - добавляет продукт в прием пищи', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(
mockDiaryRepository.addPortionToMeal(
diaryId: anyNamed('diaryId'),
mealId: anyNamed('mealId'),
productName: anyNamed('productName'),
portion: anyNamed('portion'),
quantity: anyNamed('quantity'),
productNutritionalValueId: anyNamed('productNutritionalValueId'),
),
).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.addProductToMeal(diaryId: 1, mealId: 1, productName: 'Яблоко', portion: '100г', quantity: 2);
await Future.delayed(const Duration(milliseconds: 100));
});
test('markEaten - отмечает продукт как съеденный', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(
mockDiaryRepository.markEaten(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), portionId: anyNamed('portionId')),
).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.markEaten(diaryId: 1, mealId: 1, portionId: 5);
await Future.delayed(const Duration(milliseconds: 100));
});
test('getGlossaryListByQuery - получает список глоссариев по запросу', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockGlossaryRepository.getGlossaryListByQuery(any)).thenAnswer(
(_) async => [
const GlossaryModel(
id: 1,
name: 'Яблоко',
grInPortion: 100,
energyOn100Gr: 52.0,
proteinsOn100Gr: 0.3,
fatsOn100Gr: 0.2,
carbohydratesOn100Gr: 14.0,
energyOnPortion: 52.0,
proteinsOnPortion: 0.3,
fatsOnPortion: 0.2,
carbohydratesOnPortion: 14.0,
),
],
);
final result = await diaryCubit!.getGlossaryListByQuery('яблоко');
expect(result, isA<List<GlossaryModel>>());
expect(result.length, 1);
expect(result.first.name, 'Яблоко');
});
test('fillSatiety - заполняет сытость', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(
mockDiaryRepository.fillSatiety(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), satiety: anyNamed('satiety')),
).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.fillSatiety(diaryId: 1, satiety: 5);
await Future.delayed(const Duration(milliseconds: 100));
});
test('fillMood - заполняет настроение', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(
mockDiaryRepository.fillMood(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), mood: anyNamed('mood')),
).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.fillMood(diaryId: 1, mood: 4);
await Future.delayed(const Duration(milliseconds: 100));
});
test('fillComment - заполняет комментарий', () {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
diaryCubit!.fillComment('Хороший день');
expect(diaryCubit!.comment, 'Хороший день');
});
test('updateCurrentDiary - обновляет текущий дневник', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.updateCurrentDiary();
await Future.delayed(const Duration(milliseconds: 100));
verify(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).called(1);
});
test('updateCurrentDiary - обрабатывает ошибку', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenThrow(Exception('Ошибка'));
await diaryCubit!.updateCurrentDiary();
await Future.delayed(const Duration(milliseconds: 100));
});
test('getNutrition - получает данные о питании', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
final result = await diaryCubit!.getNutrition(1);
expect(result, testNutrition);
verify(mockDiaryRepository.getNutritionData(1)).called(1);
});
test('updateProductInMeal - обновляет продукт в приеме пищи', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(
mockDiaryRepository.updateProductInMeal(
diaryId: anyNamed('diaryId'),
mealId: anyNamed('mealId'),
portionId: anyNamed('portionId'),
productName: anyNamed('productName'),
portion: anyNamed('portion'),
quantity: anyNamed('quantity'),
productNutritionalValueId: anyNamed('productNutritionalValueId'),
portionState: anyNamed('portionState'),
),
).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.updateProductInMeal(
diaryId: 1,
mealId: 1,
portionId: 5,
productName: 'Яблоко',
portion: '150г',
quantity: 3,
portionState: PortionState.eaten,
);
await Future.delayed(const Duration(milliseconds: 100));
verify(
mockDiaryRepository.updateProductInMeal(
diaryId: 1,
mealId: 1,
portionId: 5,
productName: 'Яблоко',
portion: '150г',
quantity: 3,
productNutritionalValueId: anyNamed('productNutritionalValueId'),
portionState: PortionState.eaten,
),
).called(1);
});
test('unmarkEaten - снимает отметку о съеденном', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(
mockDiaryRepository.unmarkEaten(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), portionId: anyNamed('portionId')),
).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.unmarkEaten(diaryId: 1, mealId: 1, portionId: 5);
await Future.delayed(const Duration(milliseconds: 100));
verify(mockDiaryRepository.unmarkEaten(diaryId: 1, mealId: 1, portionId: 5)).called(1);
});
test('restore - восстанавливает продукт', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(
mockDiaryRepository.restore(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), portionId: anyNamed('portionId')),
).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.restore(diaryId: 1, mealId: 1, portionId: 5);
await Future.delayed(const Duration(milliseconds: 100));
verify(mockDiaryRepository.restore(diaryId: 1, mealId: 1, portionId: 5)).called(1);
});
test('deleteProductFromMeal - удаляет продукт из приема пищи', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(
mockDiaryRepository.deleteProductFromMeal(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), portionId: anyNamed('portionId')),
).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.deleteProductFromMeal(diaryId: 1, mealId: 1, portionId: 5);
await Future.delayed(const Duration(milliseconds: 100));
verify(mockDiaryRepository.deleteProductFromMeal(diaryId: 1, mealId: 1, portionId: 5)).called(1);
});
test('sendProductToModeration - отправляет продукт на модерацию', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
const moderationModel = GlossaryModerationModel(
glossary: GlossaryModel(
id: 1,
name: 'Новый продукт',
grInPortion: 100,
energyOn100Gr: 100.0,
proteinsOn100Gr: 10.0,
fatsOn100Gr: 5.0,
carbohydratesOn100Gr: 15.0,
energyOnPortion: 100.0,
proteinsOnPortion: 10.0,
fatsOnPortion: 5.0,
carbohydratesOnPortion: 15.0,
),
);
when(
mockDiaryRepository.sendProductToModeration(
name: anyNamed('name'),
energy: anyNamed('energy'),
proteins: anyNamed('proteins'),
fats: anyNamed('fats'),
carbohydrates: anyNamed('carbohydrates'),
),
).thenAnswer((_) async => moderationModel);
final result = await diaryCubit!.sendProductToModeration(name: 'Новый продукт', energy: 100.0, proteins: 10.0, fats: 5.0, carbohydrates: 15.0);
expect(result, moderationModel);
verify(mockDiaryRepository.sendProductToModeration(name: 'Новый продукт', energy: 100.0, proteins: 10.0, fats: 5.0, carbohydrates: 15.0)).called(1);
});
test('sendProductToModeration - возвращает null при ошибке', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(
mockDiaryRepository.sendProductToModeration(
name: anyNamed('name'),
energy: anyNamed('energy'),
proteins: anyNamed('proteins'),
fats: anyNamed('fats'),
carbohydrates: anyNamed('carbohydrates'),
),
).thenThrow(Exception('Ошибка'));
final result = await diaryCubit!.sendProductToModeration(name: 'Новый продукт', energy: 100.0, proteins: 10.0, fats: 5.0, carbohydrates: 15.0);
expect(result, isNull);
});
test('fillTime - заполняет время приема пищи', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(
mockDiaryRepository.fillTime(diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId'), time: anyNamed('time')),
).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.fillTime(diaryId: 1, time: '12:00');
await Future.delayed(const Duration(milliseconds: 100));
verify(mockDiaryRepository.fillTime(diaryId: 1, mealId: 1, time: '12:00')).called(1);
});
test('fillWakeup - заполняет время пробуждения', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.fillWakeup(diaryId: anyNamed('diaryId'), time: anyNamed('time'))).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.fillWakeup(diaryId: 1, time: '07:00');
await Future.delayed(const Duration(milliseconds: 100));
verify(mockDiaryRepository.fillWakeup(diaryId: 1, time: '07:00')).called(1);
});
test('fillRetire - заполняет время отхода ко сну', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.fillRetire(diaryId: anyNamed('diaryId'), time: anyNamed('time'))).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.fillRetire(diaryId: 1, time: '23:00');
await Future.delayed(const Duration(milliseconds: 100));
verify(mockDiaryRepository.fillRetire(diaryId: 1, time: '23:00')).called(1);
});
test('getDiary - создает новый день дневника', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
final result = await diaryCubit!.getDiary();
expect(result, isNotNull);
verify(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).called(1);
verify(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).called(1);
});
test('getDiary - обрабатывает ошибку 422 и получает существующий день', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenThrow(
DioException(
requestOptions: RequestOptions(path: ''),
response: Response(requestOptions: RequestOptions(path: ''), statusCode: 422),
),
);
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
final result = await diaryCubit!.getDiary();
expect(result, isNotNull);
verify(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).called(1);
verify(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).called(1);
});
test('getDiary - возвращает null при другой ошибке', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenThrow(
DioException(
requestOptions: RequestOptions(path: ''),
response: Response(requestOptions: RequestOptions(path: ''), statusCode: 500),
),
);
final result = await diaryCubit!.getDiary();
expect(result, isNull);
});
// Тест для fetchDiaryV2 когда diaryEntity == null пропущен,
// так как toEntity() возвращает null только в специфических случаях,
// которые сложно воспроизвести в unit-тестах
test('fetchDiaryV2 - обрабатывает случай когда diaryDay == null', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenThrow(
DioException(
requestOptions: RequestOptions(path: ''),
response: Response(requestOptions: RequestOptions(path: ''), statusCode: 500),
),
);
final result = await diaryCubit!.fetchDiaryV2(needLoading: false);
expect(result, true);
expect(diaryCubit!.state, isA<DiaryStateError>());
});
// Тест для uploadPhotos пропущен, так как требует реального изображения для ImageCompressUtility
test('deletePhoto - удаляет фотографию', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
const photo = DiaryPhotoModel(id: 1, originalName: 'test.jpg', path: 'path/to/test.jpg', size: 100);
when(
mockDiaryRepository.deletePhoto(photo: anyNamed('photo'), diaryId: anyNamed('diaryId'), mealId: anyNamed('mealId')),
).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => testDiaryDay);
when(mockDiaryRepository.getNutritionData(any)).thenAnswer((_) async => testNutrition);
when(mockSettingsRepository.getProfileSettings()).thenAnswer(
(_) async => const ProfileSettingsModel(
isMoodFillable: true,
isBedtimeFillable: true,
isPublicProfile: true,
newUpdatesNotifications: null,
diaryReminderNotifications: null,
),
);
await diaryCubit!.fetchDiaryV2(needLoading: true);
await Future.delayed(const Duration(milliseconds: 100));
await diaryCubit!.deletePhoto(photo: photo, diaryId: 1);
await Future.delayed(const Duration(milliseconds: 100));
verify(mockDiaryRepository.deletePhoto(photo: photo, diaryId: 1, mealId: 1)).called(1);
});
test('setSelectedDay - возвращает true даже если getDiary возвращает null', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenThrow(
DioException(
requestOptions: RequestOptions(path: ''),
response: Response(requestOptions: RequestOptions(path: ''), statusCode: 500),
),
);
final result = await diaryCubit!.setSelectedDay(DateTime(2024, 1, 20));
// fetchDiaryV2 возвращает true когда getDiary() == null, так как эмитит состояние ошибки
expect(result, true);
expect(diaryCubit!.state, isA<DiaryStateError>());
});
test('fetchDiaryV2 - обрабатывает случай когда diaryEntity == null и нет диеты', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
// toEntity() возвращает null когда id == null
const diaryDayWithoutEntity = DiaryDayModel(
id: null,
date: '2024-01-15',
closed: 0,
comment: '',
typeOfDiary: TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: false, diaryState: null),
meals: [],
chosenPlanId: null,
dayOfChosenDiet: null,
diet: null,
);
when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => diaryDayWithoutEntity);
final result = await diaryCubit!.fetchDiaryV2(needLoading: false);
// Если diaryEntity == null (id == null) и нет диеты, fetchDiaryV2 возвращает false
// и эмитит предыдущее состояние (loading)
expect(result, false);
expect(diaryCubit!.state, const DiaryState.loading());
});
test('fetchDiaryV2 - обрабатывает случай когда diaryEntity == null но есть диета', () async {
diaryCubit = DiaryCubit(
diaryRepository: mockDiaryRepository,
glossaryRepository: mockGlossaryRepository,
profileRepository: mockProfileRepository,
dietRepository: mockDietRepository,
chatRepository: mockChatRepository,
settingsRepository: mockSettingsRepository,
);
// id должен быть null, чтобы toEntity() вернул null и код пошел по ветке setDiaryForDietOnly
const diaryDayWithDiet = DiaryDayModel(
id: null,
date: '2024-01-15',
closed: 0,
comment: '',
typeOfDiary: TypeOfDiaryModel(hasChosenDiet: true, hasChosenPlan: false, diaryState: null),
meals: [],
chosenPlanId: null,
dayOfChosenDiet: 1,
diet: DiaryDietModel(id: 1, duration: 7, name: 'Test Diet'),
);
when(mockDiaryRepository.createDiaryDay(day: anyNamed('day'))).thenAnswer((_) async => Future.value());
when(mockDiaryRepository.getDiaryDayV2(day: anyNamed('day'))).thenAnswer((_) async => diaryDayWithDiet);
when(mockDietRepository.getDiet(1)).thenAnswer(
(_) async => const Diet(
id: 1,
slug: 'test-diet',
name: 'Test Diet',
image: '',
duration: 7,
state: DietState.active,
type: DietType(),
details: '',
dailySchedule: {
1: {
1: {1: DailySchedule(name: 'Яблоко', portion: Portion.grams, quantity: 1)},
},
},
author: Author(authorSlug: 'test', authorName: 'Test', authorProfileIcon: '', authorIsMe: false),
totalLikes: 0,
totalViews: 0,
totalComments: 0,
wasLikedByMe: false,
isFavorite: false,
dailyNutrition: [],
),
);
final result = await diaryCubit!.fetchDiaryV2(needLoading: false);
await Future.delayed(const Duration(milliseconds: 100));
expect(result, true);
// setDiaryForDietOnly сначала эмитит loading, затем loadedTomorrowWithDiet
expect(diaryCubit!.state, isA<DiaryStateLoadedTomorrowWithDiet>());
});
});
}