feat(diary): tests

This commit is contained in:
mso7nueh
2026-05-04 17:36:48 +03:00
parent ea107ff07e
commit 91c8300da7
13 changed files with 2067 additions and 536 deletions

View File

@@ -0,0 +1,97 @@
import 'package:eatvio_app/features/diary/presentation/bloc/glossary_sync_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/glossary_sync_state.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/glossary_sync_banner_widget.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';
@GenerateNiceMocks([MockSpec<GlossarySyncCubit>()])
import 'glossary_sync_banner_widget_test.mocks.dart';
void main() {
late MockGlossarySyncCubit mockCubit;
setUp(() {
mockCubit = MockGlossarySyncCubit();
when(mockCubit.stream).thenAnswer((_) => const Stream<GlossarySyncState>.empty());
when(mockCubit.close()).thenAnswer((_) async {});
});
Widget buildWidget() {
return MaterialApp(
home: BlocProvider<GlossarySyncCubit>.value(
value: mockCubit,
child: const Scaffold(
body: GlossarySyncBannerWidget(),
),
),
);
}
group('GlossarySyncBannerWidget', () {
testWidgets('idle state shows nothing', (tester) async {
when(mockCubit.state).thenReturn(const GlossarySyncState.idle());
await tester.pumpWidget(buildWidget());
await tester.pump();
expect(find.byType(GlossarySyncBannerWidget), findsOneWidget);
});
testWidgets('upToDate state shows nothing', (tester) async {
when(mockCubit.state).thenReturn(const GlossarySyncState.upToDate());
await tester.pumpWidget(buildWidget());
await tester.pump();
expect(find.byType(GlossarySyncBannerWidget), findsOneWidget);
});
testWidgets('checking state shows checking text', (tester) async {
when(mockCubit.state).thenReturn(const GlossarySyncState.checking());
await tester.pumpWidget(buildWidget());
await tester.pump();
expect(find.textContaining('Проверяю'), findsOneWidget);
});
testWidgets('downloading with progress shows percentage', (tester) async {
when(mockCubit.state).thenReturn(const GlossarySyncState.downloading(progress: 0.45));
await tester.pumpWidget(buildWidget());
await tester.pump();
expect(find.textContaining('45%'), findsOneWidget);
});
testWidgets('downloading without progress shows dots', (tester) async {
when(mockCubit.state).thenReturn(const GlossarySyncState.downloading());
await tester.pumpWidget(buildWidget());
await tester.pump();
expect(find.textContaining('Загрузка'), findsOneWidget);
});
testWidgets('processing shows progress', (tester) async {
when(mockCubit.state).thenReturn(const GlossarySyncState.processing(processed: 12500, total: 200000));
await tester.pumpWidget(buildWidget());
await tester.pump();
expect(find.textContaining('Обработка'), findsOneWidget);
});
testWidgets('processing with 0 total shows generic text', (tester) async {
when(mockCubit.state).thenReturn(const GlossarySyncState.processing(processed: 0, total: 0));
await tester.pumpWidget(buildWidget());
await tester.pump();
expect(find.textContaining('Обработка данных'), findsOneWidget);
});
testWidgets('completed shows count', (tester) async {
when(mockCubit.state).thenReturn(const GlossarySyncState.completed(syncedCount: 200000));
await tester.pumpWidget(buildWidget());
await tester.pump();
expect(find.textContaining('Синхронизировано'), findsOneWidget);
});
testWidgets('error shows error message', (tester) async {
when(mockCubit.state).thenReturn(const GlossarySyncState.error(message: 'Ошибка синхронизации'));
await tester.pumpWidget(buildWidget());
await tester.pump();
expect(find.textContaining('Ошибка'), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,124 @@
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/presentation/bloc/diary_cubit.dart';
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
import 'package:eatvio_app/features/diary/presentation/widgets/offline_banner_widget.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';
@GenerateNiceMocks([MockSpec<DiaryCubit>()])
import 'offline_banner_widget_test.mocks.dart';
DiaryDayEntity _makeDiary() => DiaryDayEntity(
id: 1,
date: '2025-01-01',
wakeup: '06:30:00',
retire: '22:30:00',
closed: 0,
comment: '',
typeOfDiary: const TypeOfDiaryModel(hasChosenDiet: false, hasChosenPlan: false, diaryState: null),
meals: [
const MealModel(id: 1, time: '08:00', typeNumber: 1, satiety: 0, mood: 0, portions: [], photos: []),
],
chosenPlanId: null,
dayOfChosenDiet: null,
diet: null,
);
void main() {
late MockDiaryCubit mockDiaryCubit;
setUp(() {
mockDiaryCubit = MockDiaryCubit();
when(mockDiaryCubit.stream).thenAnswer((_) => const Stream<DiaryState>.empty());
when(mockDiaryCubit.close()).thenAnswer((_) async {});
});
Widget buildWidget() {
return MaterialApp(
home: BlocProvider<DiaryCubit>.value(
value: mockDiaryCubit,
child: const Scaffold(
body: OfflineBannerWidget(),
),
),
);
}
group('OfflineBannerWidget', () {
testWidgets('shows nothing when online and no pending ops', (tester) async {
when(mockDiaryCubit.state).thenReturn(
DiaryState.loaded(
diary: _makeDiary(),
selectedDay: DateTime(2025, 1, 1),
selectedMeal: 1,
isOfflineMode: false,
pendingOpsCount: 0,
),
);
await tester.pumpWidget(buildWidget());
await tester.pump();
// SizedBox.shrink should be rendered — no banner text visible
expect(find.textContaining('Офлайн'), findsNothing);
expect(find.textContaining('Синхронизация'), findsNothing);
});
testWidgets('shows offline banner with pending ops', (tester) async {
when(mockDiaryCubit.state).thenReturn(
DiaryState.loaded(
diary: _makeDiary(),
selectedDay: DateTime(2025, 1, 1),
selectedMeal: 1,
isOfflineMode: true,
pendingOpsCount: 3,
),
);
await tester.pumpWidget(buildWidget());
await tester.pump();
expect(find.textContaining('Офлайн'), findsOneWidget);
expect(find.textContaining('3'), findsWidgets);
});
testWidgets('shows offline without pending ops', (tester) async {
when(mockDiaryCubit.state).thenReturn(
DiaryState.loaded(
diary: _makeDiary(),
selectedDay: DateTime(2025, 1, 1),
selectedMeal: 1,
isOfflineMode: true,
pendingOpsCount: 0,
),
);
await tester.pumpWidget(buildWidget());
await tester.pump();
expect(find.textContaining('кэша'), findsOneWidget);
});
testWidgets('shows sync banner when online with pending ops', (tester) async {
when(mockDiaryCubit.state).thenReturn(
DiaryState.loaded(
diary: _makeDiary(),
selectedDay: DateTime(2025, 1, 1),
selectedMeal: 1,
isOfflineMode: false,
pendingOpsCount: 5,
),
);
await tester.pumpWidget(buildWidget());
await tester.pump();
expect(find.textContaining('Синхронизация'), findsOneWidget);
});
testWidgets('hides when state is not loaded', (tester) async {
when(mockDiaryCubit.state).thenReturn(const DiaryState.loading());
await tester.pumpWidget(buildWidget());
await tester.pump();
// SizedBox.shrink should be rendered
expect(find.textContaining('Офлайн'), findsNothing);
expect(find.textContaining('Синхронизация'), findsNothing);
});
});
}