forked from eatvio/eatvio_app
feat(diary): editing of previous and current finished days
This commit is contained in:
59
test/features/diary/presentation/diary_edit_access_test.dart
Normal file
59
test/features/diary/presentation/diary_edit_access_test.dart
Normal file
@@ -0,0 +1,59 @@
|
||||
import 'package:eatvio_app/features/diary/presentation/diary_edit_access.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
final now = DateTime(2026, 9, 30, 12);
|
||||
|
||||
bool canEdit({
|
||||
bool isConsultantView = false,
|
||||
bool isDiaryCommented = false,
|
||||
bool isDiaryFinished = false,
|
||||
int closed = 0,
|
||||
String diaryDate = '2026-09-28',
|
||||
}) {
|
||||
return canEditDiaryDay(
|
||||
isConsultantView: isConsultantView,
|
||||
isDiaryCommented: isDiaryCommented,
|
||||
isDiaryFinished: isDiaryFinished,
|
||||
closed: closed,
|
||||
diaryDate: diaryDate,
|
||||
now: now,
|
||||
);
|
||||
}
|
||||
|
||||
test('finished today and yesterday stay editable', () {
|
||||
expect(canEdit(isDiaryFinished: true, diaryDate: '2026-09-30'), isTrue);
|
||||
expect(canEdit(isDiaryFinished: true, diaryDate: '2026-09-29'), isTrue);
|
||||
});
|
||||
|
||||
test('finished days older than yesterday stay read-only', () {
|
||||
expect(canEdit(isDiaryFinished: true, diaryDate: '2026-09-28'), isFalse);
|
||||
});
|
||||
|
||||
test('commented days stay read-only inside the window', () {
|
||||
expect(canEdit(isDiaryCommented: true, diaryDate: '2026-09-30'), isFalse);
|
||||
expect(
|
||||
canEdit(
|
||||
isDiaryCommented: true,
|
||||
isDiaryFinished: true,
|
||||
diaryDate: '2026-09-29',
|
||||
),
|
||||
isFalse,
|
||||
);
|
||||
});
|
||||
|
||||
test('an open day outside the window stays editable', () {
|
||||
expect(canEdit(diaryDate: '2026-09-01'), isTrue);
|
||||
});
|
||||
|
||||
test('a closed flag blocks editing even inside the window', () {
|
||||
expect(
|
||||
canEdit(isDiaryFinished: true, closed: 1, diaryDate: '2026-09-30'),
|
||||
isFalse,
|
||||
);
|
||||
});
|
||||
|
||||
test('consultant view stays read-only', () {
|
||||
expect(canEdit(isConsultantView: true, diaryDate: '2026-09-30'), isFalse);
|
||||
});
|
||||
}
|
||||
@@ -25,16 +25,25 @@ import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'diary_screen_smoke_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<DiaryCubit>(), MockSpec<ConsultantCommentsCubit>()])
|
||||
@GenerateNiceMocks([
|
||||
MockSpec<DiaryCubit>(),
|
||||
MockSpec<ConsultantCommentsCubit>(),
|
||||
])
|
||||
void main() {
|
||||
group('DiaryScreen smoke', () {
|
||||
setUpAll(() async {
|
||||
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
|
||||
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'));
|
||||
sl.registerLazySingleton<AppConfig>(
|
||||
() =>
|
||||
AppConfig(buildType: AppBuildType.tests)
|
||||
..setBaseUrl('http://localhost'),
|
||||
);
|
||||
});
|
||||
|
||||
Widget wrap(Widget child) {
|
||||
@@ -51,23 +60,53 @@ void main() {
|
||||
);
|
||||
}
|
||||
|
||||
DiaryStateLoaded loadedState({required bool hasChosenPlan}) {
|
||||
DiaryStateLoaded loadedState({
|
||||
required bool hasChosenPlan,
|
||||
String date = '2025-01-01',
|
||||
bool isDiaryFinished = false,
|
||||
bool isDiaryCommented = false,
|
||||
int closed = 0,
|
||||
}) {
|
||||
final diary = DiaryDayEntity(
|
||||
id: 1,
|
||||
date: '2025-01-01',
|
||||
date: date,
|
||||
wakeup: '07:00',
|
||||
retire: '23:00',
|
||||
closed: 0,
|
||||
closed: closed,
|
||||
comment: '',
|
||||
typeOfDiary: TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: hasChosenPlan, diaryState: null),
|
||||
meals: const [MealModel(id: 1, time: '08:00', typeNumber: 1, satiety: 0, mood: 0, portions: [], photos: [])],
|
||||
typeOfDiary: TypeOfDiaryModel(
|
||||
hasChosenDiet: false,
|
||||
hasChosenPlan: hasChosenPlan,
|
||||
diaryState: null,
|
||||
),
|
||||
meals: const [
|
||||
MealModel(
|
||||
id: 1,
|
||||
time: '08:00',
|
||||
typeNumber: 1,
|
||||
satiety: 0,
|
||||
mood: 0,
|
||||
portions: [],
|
||||
photos: [],
|
||||
),
|
||||
],
|
||||
chosenPlanId: hasChosenPlan ? 10 : 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),
|
||||
dailyNutritionIntake: NutritionModel(
|
||||
energy: 0,
|
||||
proteins: 0,
|
||||
fats: 0,
|
||||
carbohydrates: 0,
|
||||
),
|
||||
dailyNutritionRecommendation: NutritionModel(
|
||||
energy: 0,
|
||||
proteins: 0,
|
||||
fats: 0,
|
||||
carbohydrates: 0,
|
||||
),
|
||||
);
|
||||
return DiaryState.loaded(
|
||||
diary: diary,
|
||||
@@ -75,8 +114,8 @@ void main() {
|
||||
selectedDay: DateTime(2025, 1, 1),
|
||||
selectedMeal: 1,
|
||||
isConsultantView: false,
|
||||
isDiaryFinished: false,
|
||||
isDiaryCommented: false,
|
||||
isDiaryFinished: isDiaryFinished,
|
||||
isDiaryCommented: isDiaryCommented,
|
||||
isWakeUpAndRetireEnabled: true,
|
||||
isMoodEnabled: true,
|
||||
)
|
||||
@@ -86,13 +125,26 @@ void main() {
|
||||
testWidgets('renders loading state', (tester) async {
|
||||
final diaryCubit = MockDiaryCubit();
|
||||
when(diaryCubit.state).thenReturn(const DiaryState.loading());
|
||||
when(diaryCubit.stream).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(
|
||||
diaryCubit.stream,
|
||||
).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(diaryCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
when(diaryCubit.fetchDiaryV2(needLoading: anyNamed('needLoading'), diaryId: anyNamed('diaryId'))).thenAnswer((_) async => true);
|
||||
when(
|
||||
diaryCubit.fetchDiaryV2(
|
||||
needLoading: anyNamed('needLoading'),
|
||||
diaryId: anyNamed('diaryId'),
|
||||
),
|
||||
).thenAnswer((_) async => true);
|
||||
|
||||
final commentsCubit = MockConsultantCommentsCubit();
|
||||
when(commentsCubit.state).thenReturn(ConsultantCommentsState(commentsModel: ConsultantCommentModel(comment: '')));
|
||||
when(commentsCubit.stream).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.state).thenReturn(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
),
|
||||
);
|
||||
when(
|
||||
commentsCubit.stream,
|
||||
).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
|
||||
sl.registerFactory<DiaryCubit>(() => diaryCubit);
|
||||
@@ -107,13 +159,27 @@ void main() {
|
||||
testWidgets('renders loaded state (chosen plan)', (tester) async {
|
||||
final diaryCubit = MockDiaryCubit();
|
||||
when(diaryCubit.state).thenReturn(loadedState(hasChosenPlan: true));
|
||||
when(diaryCubit.stream).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(
|
||||
diaryCubit.stream,
|
||||
).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(diaryCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
when(diaryCubit.fetchDiaryV2(needLoading: anyNamed('needLoading'), diaryId: anyNamed('diaryId'))).thenAnswer((_) async => true);
|
||||
when(
|
||||
diaryCubit.fetchDiaryV2(
|
||||
needLoading: anyNamed('needLoading'),
|
||||
diaryId: anyNamed('diaryId'),
|
||||
),
|
||||
).thenAnswer((_) async => true);
|
||||
|
||||
final commentsCubit = MockConsultantCommentsCubit();
|
||||
when(commentsCubit.state).thenReturn(ConsultantCommentsState(commentsModel: ConsultantCommentModel(comment: ''), dayCommentNeedsToBeFilled: false));
|
||||
when(commentsCubit.stream).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.state).thenReturn(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
dayCommentNeedsToBeFilled: false,
|
||||
),
|
||||
);
|
||||
when(
|
||||
commentsCubit.stream,
|
||||
).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
|
||||
sl.registerFactory<DiaryCubit>(() => diaryCubit);
|
||||
@@ -124,19 +190,37 @@ void main() {
|
||||
|
||||
expect(find.byType(DiaryScreen), findsOneWidget);
|
||||
|
||||
expect(find.text('Дополнительная информация для консультанта'), findsOneWidget);
|
||||
expect(
|
||||
find.text('Дополнительная информация для консультанта'),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('renders error state and reload button', (tester) async {
|
||||
final diaryCubit = MockDiaryCubit();
|
||||
when(diaryCubit.state).thenReturn(const DiaryState.error(errorMessage: 'err'));
|
||||
when(diaryCubit.stream).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(
|
||||
diaryCubit.state,
|
||||
).thenReturn(const DiaryState.error(errorMessage: 'err'));
|
||||
when(
|
||||
diaryCubit.stream,
|
||||
).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(diaryCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
when(diaryCubit.fetchDiaryV2(needLoading: anyNamed('needLoading'), diaryId: anyNamed('diaryId'))).thenAnswer((_) async => true);
|
||||
when(
|
||||
diaryCubit.fetchDiaryV2(
|
||||
needLoading: anyNamed('needLoading'),
|
||||
diaryId: anyNamed('diaryId'),
|
||||
),
|
||||
).thenAnswer((_) async => true);
|
||||
|
||||
final commentsCubit = MockConsultantCommentsCubit();
|
||||
when(commentsCubit.state).thenReturn(ConsultantCommentsState(commentsModel: ConsultantCommentModel(comment: '')));
|
||||
when(commentsCubit.stream).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.state).thenReturn(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
),
|
||||
);
|
||||
when(
|
||||
commentsCubit.stream,
|
||||
).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
|
||||
sl.registerFactory<DiaryCubit>(() => diaryCubit);
|
||||
@@ -153,19 +237,52 @@ void main() {
|
||||
final diaryCubit = MockDiaryCubit();
|
||||
const futureDiary = 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: [], photos: [])],
|
||||
typeOfDiary: TypeOfDiaryModel(
|
||||
hasChosenDiet: true,
|
||||
hasChosenPlan: false,
|
||||
diaryState: null,
|
||||
),
|
||||
meals: [
|
||||
MealModel(
|
||||
id: 1,
|
||||
time: '08:00',
|
||||
typeNumber: 1,
|
||||
satiety: 0,
|
||||
mood: 0,
|
||||
portions: [],
|
||||
photos: [],
|
||||
),
|
||||
],
|
||||
diet: null,
|
||||
dayOfChosenDiet: 1,
|
||||
);
|
||||
when(diaryCubit.state).thenReturn(DiaryState.loadedTomorrowWithDiet(diary: futureDiary, selectedDay: DateTime(2025, 1, 2), selectedMeal: 1));
|
||||
when(diaryCubit.stream).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(diaryCubit.state).thenReturn(
|
||||
DiaryState.loadedTomorrowWithDiet(
|
||||
diary: futureDiary,
|
||||
selectedDay: DateTime(2025, 1, 2),
|
||||
selectedMeal: 1,
|
||||
),
|
||||
);
|
||||
when(
|
||||
diaryCubit.stream,
|
||||
).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(diaryCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
when(diaryCubit.fetchDiaryV2(needLoading: anyNamed('needLoading'), diaryId: anyNamed('diaryId'))).thenAnswer((_) async => true);
|
||||
when(
|
||||
diaryCubit.fetchDiaryV2(
|
||||
needLoading: anyNamed('needLoading'),
|
||||
diaryId: anyNamed('diaryId'),
|
||||
),
|
||||
).thenAnswer((_) async => true);
|
||||
|
||||
final commentsCubit = MockConsultantCommentsCubit();
|
||||
when(commentsCubit.state).thenReturn(ConsultantCommentsState(commentsModel: ConsultantCommentModel(comment: '')));
|
||||
when(commentsCubit.stream).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.state).thenReturn(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
),
|
||||
);
|
||||
when(
|
||||
commentsCubit.stream,
|
||||
).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
|
||||
sl.registerFactory<DiaryCubit>(() => diaryCubit);
|
||||
@@ -187,17 +304,35 @@ void main() {
|
||||
planName: 'Plan',
|
||||
planDuration: 30,
|
||||
currentPlanDay: 1,
|
||||
consultantComments: ConsultantComments(dayComment: 'Nice', mealsComments: const [], portionsComments: const []),
|
||||
consultantComments: ConsultantComments(
|
||||
dayComment: 'Nice',
|
||||
mealsComments: const [],
|
||||
portionsComments: const [],
|
||||
),
|
||||
),
|
||||
);
|
||||
when(diaryCubit.state).thenReturn(state);
|
||||
when(diaryCubit.stream).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(
|
||||
diaryCubit.stream,
|
||||
).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(diaryCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
when(diaryCubit.fetchDiaryV2(needLoading: anyNamed('needLoading'), diaryId: anyNamed('diaryId'))).thenAnswer((_) async => true);
|
||||
when(
|
||||
diaryCubit.fetchDiaryV2(
|
||||
needLoading: anyNamed('needLoading'),
|
||||
diaryId: anyNamed('diaryId'),
|
||||
),
|
||||
).thenAnswer((_) async => true);
|
||||
|
||||
final commentsCubit = MockConsultantCommentsCubit();
|
||||
when(commentsCubit.state).thenReturn(ConsultantCommentsState(commentsModel: ConsultantCommentModel(comment: ''), dayCommentNeedsToBeFilled: false));
|
||||
when(commentsCubit.stream).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.state).thenReturn(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
dayCommentNeedsToBeFilled: false,
|
||||
),
|
||||
);
|
||||
when(
|
||||
commentsCubit.stream,
|
||||
).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
when(commentsCubit.submitComments(any)).thenAnswer((_) async => true);
|
||||
|
||||
@@ -215,13 +350,26 @@ void main() {
|
||||
final diaryCubit = MockDiaryCubit();
|
||||
final state = loadedState(hasChosenPlan: false);
|
||||
when(diaryCubit.state).thenReturn(state);
|
||||
when(diaryCubit.stream).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(
|
||||
diaryCubit.stream,
|
||||
).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(diaryCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
when(diaryCubit.fetchDiaryV2(needLoading: anyNamed('needLoading'), diaryId: anyNamed('diaryId'))).thenAnswer((_) async => true);
|
||||
when(
|
||||
diaryCubit.fetchDiaryV2(
|
||||
needLoading: anyNamed('needLoading'),
|
||||
diaryId: anyNamed('diaryId'),
|
||||
),
|
||||
).thenAnswer((_) async => true);
|
||||
|
||||
final commentsCubit = MockConsultantCommentsCubit();
|
||||
when(commentsCubit.state).thenReturn(ConsultantCommentsState(commentsModel: ConsultantCommentModel(comment: '')));
|
||||
when(commentsCubit.stream).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.state).thenReturn(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
),
|
||||
);
|
||||
when(
|
||||
commentsCubit.stream,
|
||||
).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
|
||||
sl.registerFactory<DiaryCubit>(() => diaryCubit);
|
||||
@@ -234,5 +382,96 @@ void main() {
|
||||
|
||||
expect(find.byType(Text), findsWidgets);
|
||||
});
|
||||
|
||||
testWidgets('shows add button for a finished day inside the edit window', (
|
||||
tester,
|
||||
) async {
|
||||
final yesterday = DateTime.now().subtract(const Duration(days: 1));
|
||||
final diaryCubit = MockDiaryCubit();
|
||||
when(diaryCubit.state).thenReturn(
|
||||
loadedState(
|
||||
hasChosenPlan: false,
|
||||
date: _calendarDate(yesterday),
|
||||
isDiaryFinished: true,
|
||||
),
|
||||
);
|
||||
when(
|
||||
diaryCubit.stream,
|
||||
).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(diaryCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
when(
|
||||
diaryCubit.fetchDiaryV2(
|
||||
needLoading: anyNamed('needLoading'),
|
||||
diaryId: anyNamed('diaryId'),
|
||||
),
|
||||
).thenAnswer((_) async => true);
|
||||
|
||||
final commentsCubit = MockConsultantCommentsCubit();
|
||||
when(commentsCubit.state).thenReturn(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
),
|
||||
);
|
||||
when(
|
||||
commentsCubit.stream,
|
||||
).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
|
||||
sl.registerFactory<DiaryCubit>(() => diaryCubit);
|
||||
sl.registerFactory<ConsultantCommentsCubit>(() => commentsCubit);
|
||||
|
||||
await tester.pumpWidget(wrap(DiaryScreen(date: yesterday)));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
|
||||
expect(find.text('Добавить'), findsOneWidget);
|
||||
expect(find.text('Закончить день'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('hides add button for a commented day', (tester) async {
|
||||
final yesterday = DateTime.now().subtract(const Duration(days: 1));
|
||||
final diaryCubit = MockDiaryCubit();
|
||||
when(diaryCubit.state).thenReturn(
|
||||
loadedState(
|
||||
hasChosenPlan: false,
|
||||
date: _calendarDate(yesterday),
|
||||
isDiaryCommented: true,
|
||||
),
|
||||
);
|
||||
when(
|
||||
diaryCubit.stream,
|
||||
).thenAnswer((_) => const Stream<DiaryState>.empty());
|
||||
when(diaryCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
when(
|
||||
diaryCubit.fetchDiaryV2(
|
||||
needLoading: anyNamed('needLoading'),
|
||||
diaryId: anyNamed('diaryId'),
|
||||
),
|
||||
).thenAnswer((_) async => true);
|
||||
|
||||
final commentsCubit = MockConsultantCommentsCubit();
|
||||
when(commentsCubit.state).thenReturn(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
),
|
||||
);
|
||||
when(
|
||||
commentsCubit.stream,
|
||||
).thenAnswer((_) => const Stream<ConsultantCommentsState>.empty());
|
||||
when(commentsCubit.close()).thenAnswer((_) async => Future<void>.value());
|
||||
|
||||
sl.registerFactory<DiaryCubit>(() => diaryCubit);
|
||||
sl.registerFactory<ConsultantCommentsCubit>(() => commentsCubit);
|
||||
|
||||
await tester.pumpWidget(wrap(DiaryScreen(date: yesterday)));
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
|
||||
expect(find.text('Добавить'), findsNothing);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
String _calendarDate(DateTime date) {
|
||||
final month = date.month.toString().padLeft(2, '0');
|
||||
final day = date.day.toString().padLeft(2, '0');
|
||||
return '${date.year}-$month-$day';
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
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';
|
||||
@@ -27,7 +26,8 @@ class FakeDiaryCubit extends Cubit<DiaryState> implements DiaryCubit {
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
||||
|
||||
class FakeConsultantCommentsCubit extends Cubit<ConsultantCommentsState> implements ConsultantCommentsCubit {
|
||||
class FakeConsultantCommentsCubit extends Cubit<ConsultantCommentsState>
|
||||
implements ConsultantCommentsCubit {
|
||||
FakeConsultantCommentsCubit(super.initialState);
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
@@ -60,9 +60,16 @@ void main() {
|
||||
</svg>
|
||||
''';
|
||||
|
||||
final bundle = _FakeAssetBundle({'assets/icons/revert_product.svg': fakeSvg, 'assets/icons/edit.svg': fakeSvg});
|
||||
final bundle = _FakeAssetBundle({
|
||||
'assets/icons/revert_product.svg': fakeSvg,
|
||||
'assets/icons/edit.svg': fakeSvg,
|
||||
});
|
||||
|
||||
Widget wrap({required DiaryCubit diaryCubit, required ConsultantCommentsCubit consultantCommentsCubit, required Widget child}) {
|
||||
Widget wrap({
|
||||
required DiaryCubit diaryCubit,
|
||||
required ConsultantCommentsCubit consultantCommentsCubit,
|
||||
required Widget child,
|
||||
}) {
|
||||
return DefaultAssetBundle(
|
||||
bundle: bundle,
|
||||
child: MaterialApp(
|
||||
@@ -77,7 +84,9 @@ void main() {
|
||||
home: MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<DiaryCubit>.value(value: diaryCubit),
|
||||
BlocProvider<ConsultantCommentsCubit>.value(value: consultantCommentsCubit),
|
||||
BlocProvider<ConsultantCommentsCubit>.value(
|
||||
value: consultantCommentsCubit,
|
||||
),
|
||||
],
|
||||
child: Scaffold(body: child),
|
||||
),
|
||||
@@ -85,17 +94,36 @@ void main() {
|
||||
);
|
||||
}
|
||||
|
||||
DiaryStateLoaded loadedState({required PortionModel portion, required bool consultantView}) {
|
||||
DiaryStateLoaded loadedState({
|
||||
required PortionModel portion,
|
||||
required bool consultantView,
|
||||
String date = '2025-01-01',
|
||||
bool isDiaryFinished = false,
|
||||
bool isDiaryCommented = false,
|
||||
int closed = 0,
|
||||
}) {
|
||||
final diary = DiaryDayEntity(
|
||||
id: 1,
|
||||
date: '2025-01-01',
|
||||
date: date,
|
||||
wakeup: '07:00',
|
||||
retire: '23:00',
|
||||
closed: 0,
|
||||
closed: closed,
|
||||
comment: '',
|
||||
typeOfDiary: const TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: true, diaryState: DiaryStateEnum.started),
|
||||
typeOfDiary: const TypeOfDiaryModel(
|
||||
hasChosenDiet: false,
|
||||
hasChosenPlan: true,
|
||||
diaryState: DiaryStateEnum.started,
|
||||
),
|
||||
meals: [
|
||||
MealModel(id: 1, time: '08:00', typeNumber: 1, satiety: 0, mood: 0, portions: [portion], photos: const []),
|
||||
MealModel(
|
||||
id: 1,
|
||||
time: '08:00',
|
||||
typeNumber: 1,
|
||||
satiety: 0,
|
||||
mood: 0,
|
||||
portions: [portion],
|
||||
photos: const [],
|
||||
),
|
||||
],
|
||||
chosenPlanId: 1,
|
||||
dayOfChosenDiet: null,
|
||||
@@ -103,8 +131,18 @@ void main() {
|
||||
);
|
||||
|
||||
const nutrition = NutritionDataModel(
|
||||
dailyNutritionIntake: NutritionModel(energy: 0, proteins: 0, fats: 0, carbohydrates: 0),
|
||||
dailyNutritionRecommendation: NutritionModel(energy: 0, proteins: 0, fats: 0, carbohydrates: 0),
|
||||
dailyNutritionIntake: NutritionModel(
|
||||
energy: 0,
|
||||
proteins: 0,
|
||||
fats: 0,
|
||||
carbohydrates: 0,
|
||||
),
|
||||
dailyNutritionRecommendation: NutritionModel(
|
||||
energy: 0,
|
||||
proteins: 0,
|
||||
fats: 0,
|
||||
carbohydrates: 0,
|
||||
),
|
||||
);
|
||||
|
||||
return DiaryState.loaded(
|
||||
@@ -113,13 +151,17 @@ void main() {
|
||||
selectedDay: DateTime(2025, 1, 1),
|
||||
selectedMeal: 1,
|
||||
isConsultantView: consultantView,
|
||||
isDiaryFinished: false,
|
||||
isDiaryCommented: false,
|
||||
isDiaryFinished: isDiaryFinished,
|
||||
isDiaryCommented: isDiaryCommented,
|
||||
consultantReview: ConsultantReviewModel(
|
||||
planName: 'Plan',
|
||||
planDuration: 10,
|
||||
currentPlanDay: 1,
|
||||
consultantComments: ConsultantComments(dayComment: null, mealsComments: const [], portionsComments: const []),
|
||||
consultantComments: ConsultantComments(
|
||||
dayComment: null,
|
||||
mealsComments: const [],
|
||||
portionsComments: const [],
|
||||
),
|
||||
),
|
||||
)
|
||||
as DiaryStateLoaded;
|
||||
@@ -140,9 +182,21 @@ void main() {
|
||||
DiaryState.loadedTomorrowWithDiet(
|
||||
diary: const DiaryFutureDietDayEntity(
|
||||
date: '2025-01-02',
|
||||
typeOfDiary: TypeOfDiaryModel(hasChosenDiet: true, hasChosenPlan: false, diaryState: null),
|
||||
typeOfDiary: TypeOfDiaryModel(
|
||||
hasChosenDiet: true,
|
||||
hasChosenPlan: false,
|
||||
diaryState: null,
|
||||
),
|
||||
meals: [
|
||||
MealModel(id: 1, time: '08:00', typeNumber: 1, satiety: 0, mood: 0, portions: [portion], photos: []),
|
||||
MealModel(
|
||||
id: 1,
|
||||
time: '08:00',
|
||||
typeNumber: 1,
|
||||
satiety: 0,
|
||||
mood: 0,
|
||||
portions: [portion],
|
||||
photos: [],
|
||||
),
|
||||
],
|
||||
diet: null,
|
||||
dayOfChosenDiet: 1,
|
||||
@@ -151,7 +205,11 @@ void main() {
|
||||
selectedMeal: 1,
|
||||
),
|
||||
);
|
||||
final commentsCubit = FakeConsultantCommentsCubit(ConsultantCommentsState(commentsModel: ConsultantCommentModel(comment: '')));
|
||||
final commentsCubit = FakeConsultantCommentsCubit(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
@@ -177,8 +235,14 @@ void main() {
|
||||
fromDiet: false,
|
||||
portionState: PortionState.eatenDeleted,
|
||||
);
|
||||
final diaryCubit = FakeDiaryCubit(loadedState(portion: portion, consultantView: false));
|
||||
final commentsCubit = FakeConsultantCommentsCubit(ConsultantCommentsState(commentsModel: ConsultantCommentModel(comment: '')));
|
||||
final diaryCubit = FakeDiaryCubit(
|
||||
loadedState(portion: portion, consultantView: false),
|
||||
);
|
||||
final commentsCubit = FakeConsultantCommentsCubit(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
@@ -194,32 +258,89 @@ void main() {
|
||||
expect(find.byType(ProductWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('consultant view toggles comment widget and shows existing comment container', (tester) async {
|
||||
testWidgets(
|
||||
'consultant view toggles comment widget and shows existing comment container',
|
||||
(tester) async {
|
||||
const portion = PortionModel(
|
||||
id: 1,
|
||||
productNutritionalValueId: null,
|
||||
productCaloriesInfo: null,
|
||||
productName: 'Portion',
|
||||
quantity: 100,
|
||||
portion: 'gr',
|
||||
fromDiet: false,
|
||||
portionState: PortionState.filledDiet,
|
||||
);
|
||||
final state = loadedState(portion: portion, consultantView: true)
|
||||
.copyWith(
|
||||
consultantReview: ConsultantReviewModel(
|
||||
planName: 'Plan',
|
||||
planDuration: 10,
|
||||
currentPlanDay: 1,
|
||||
consultantComments: ConsultantComments(
|
||||
dayComment: null,
|
||||
mealsComments: const [],
|
||||
portionsComments: [
|
||||
PortionComment(portionId: 1, comment: 'Looks good'),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final diaryCubit = FakeDiaryCubit(state);
|
||||
final commentsCubit = FakeConsultantCommentsCubit(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
diaryCubit: diaryCubit,
|
||||
consultantCommentsCubit: commentsCubit,
|
||||
child: const ProductWidget(portion: portion),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(CommentContainer), findsOneWidget);
|
||||
expect(find.text('Looks good'), findsOneWidget);
|
||||
|
||||
// Tap edit icon to enable PortionCommentWidget.
|
||||
await tester.tap(find.byType(GestureDetector).first);
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(PortionCommentWidget), findsOneWidget);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('can edit a portion on a finished day inside the edit window', (
|
||||
tester,
|
||||
) async {
|
||||
const portion = PortionModel(
|
||||
id: 1,
|
||||
productNutritionalValueId: null,
|
||||
productCaloriesInfo: null,
|
||||
productName: 'Portion',
|
||||
productName: 'Apple',
|
||||
quantity: 100,
|
||||
portion: 'gr',
|
||||
fromDiet: false,
|
||||
portionState: PortionState.filledDiet,
|
||||
portionState: PortionState.eaten,
|
||||
);
|
||||
final state = loadedState(portion: portion, consultantView: true).copyWith(
|
||||
consultantReview: ConsultantReviewModel(
|
||||
planName: 'Plan',
|
||||
planDuration: 10,
|
||||
currentPlanDay: 1,
|
||||
consultantComments: ConsultantComments(
|
||||
dayComment: null,
|
||||
mealsComments: const [],
|
||||
portionsComments: [PortionComment(portionId: 1, comment: 'Looks good')],
|
||||
),
|
||||
final yesterday = DateTime.now().subtract(const Duration(days: 1));
|
||||
final diaryCubit = FakeDiaryCubit(
|
||||
loadedState(
|
||||
portion: portion,
|
||||
consultantView: false,
|
||||
date: _calendarDate(yesterday),
|
||||
isDiaryFinished: true,
|
||||
),
|
||||
);
|
||||
final commentsCubit = FakeConsultantCommentsCubit(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
),
|
||||
);
|
||||
|
||||
final diaryCubit = FakeDiaryCubit(state);
|
||||
final commentsCubit = FakeConsultantCommentsCubit(ConsultantCommentsState(commentsModel: ConsultantCommentModel(comment: '')));
|
||||
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
@@ -230,15 +351,51 @@ void main() {
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
expect(tester.widget<ListTile>(find.byType(ListTile)).onTap, isNotNull);
|
||||
});
|
||||
|
||||
expect(find.byType(CommentContainer), findsOneWidget);
|
||||
expect(find.text('Looks good'), findsOneWidget);
|
||||
testWidgets('cannot edit a portion on a commented day', (tester) async {
|
||||
const portion = PortionModel(
|
||||
id: 1,
|
||||
productNutritionalValueId: null,
|
||||
productCaloriesInfo: null,
|
||||
productName: 'Apple',
|
||||
quantity: 100,
|
||||
portion: 'gr',
|
||||
fromDiet: false,
|
||||
portionState: PortionState.eaten,
|
||||
);
|
||||
final yesterday = DateTime.now().subtract(const Duration(days: 1));
|
||||
final diaryCubit = FakeDiaryCubit(
|
||||
loadedState(
|
||||
portion: portion,
|
||||
consultantView: false,
|
||||
date: _calendarDate(yesterday),
|
||||
isDiaryCommented: true,
|
||||
),
|
||||
);
|
||||
final commentsCubit = FakeConsultantCommentsCubit(
|
||||
ConsultantCommentsState(
|
||||
commentsModel: ConsultantCommentModel(comment: ''),
|
||||
),
|
||||
);
|
||||
|
||||
// Tap edit icon to enable PortionCommentWidget.
|
||||
await tester.tap(find.byType(GestureDetector).first);
|
||||
await tester.pumpWidget(
|
||||
wrap(
|
||||
diaryCubit: diaryCubit,
|
||||
consultantCommentsCubit: commentsCubit,
|
||||
child: const ProductWidget(portion: portion),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
expect(find.byType(PortionCommentWidget), findsOneWidget);
|
||||
expect(tester.widget<ListTile>(find.byType(ListTile)).onTap, isNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
String _calendarDate(DateTime date) {
|
||||
final month = date.month.toString().padLeft(2, '0');
|
||||
final day = date.day.toString().padLeft(2, '0');
|
||||
return '${date.year}-$month-$day';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user