chore(version): update app version to 1.3.5+85 and improve test coverage reporting in CI

This commit is contained in:
mso7nueh
2025-12-08 11:19:08 +03:00
parent abe4985f0e
commit c2a506cdbf
148 changed files with 12395 additions and 1889 deletions

View File

@@ -0,0 +1,93 @@
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:eatvio_app/core/di/app_config_registration.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/cancel_plan_bottom_sheet/cancel_plan_bottom_sheet.dart';
import 'package:eatvio_app/features/cancel_plan_bottom_sheet/cubit/cancel_plan_cubit.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 'cancel_plan_bottom_sheet_test.mocks.dart';
@GenerateMocks([CancelPlanCubit])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('CancelPlanBottomSheet', () {
late MockCancelPlanCubit mockCancelPlanCubit;
setUp(() async {
await sl.reset();
AppConfigRegistration.registerAppConfig(buildType: AppBuildType.tests);
mockCancelPlanCubit = MockCancelPlanCubit();
});
Widget createTestWidget({
bool enableForm = false,
required int planId,
}) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru'), Locale('en')],
locale: const Locale('ru'),
home: BlocProvider<CancelPlanCubit>.value(
value: mockCancelPlanCubit,
child: Scaffold(
body: CancelPlanBottomSheet(
enableForm: enableForm,
planId: planId,
),
),
),
);
}
testWidgets('displays cancel plan bottom sheet without form', (tester) async {
when(mockCancelPlanCubit.cancelChosenPlan(id: anyNamed('id')))
.thenAnswer((_) async => true);
await tester.pumpWidget(createTestWidget(planId: 1));
await tester.pumpAndSettle();
expect(find.byType(CancelPlanBottomSheet), findsOneWidget);
});
testWidgets('displays cancel plan bottom sheet with form', (tester) async {
when(mockCancelPlanCubit.cancelChosenPlan(
id: anyNamed('id'),
reason: anyNamed('reason'),
price: anyNamed('price'),
)).thenAnswer((_) async => true);
await tester.pumpWidget(createTestWidget(enableForm: true, planId: 1));
await tester.pumpAndSettle();
expect(find.byType(CancelPlanBottomSheet), findsOneWidget);
});
testWidgets('displays form fields when enableForm is true', (tester) async {
when(mockCancelPlanCubit.cancelChosenPlan(
id: anyNamed('id'),
reason: anyNamed('reason'),
price: anyNamed('price'),
)).thenAnswer((_) async => true);
await tester.pumpWidget(createTestWidget(enableForm: true, planId: 1));
await tester.pumpAndSettle();
expect(find.byType(CancelPlanBottomSheet), findsOneWidget);
});
});
}

View File

@@ -1,84 +1,81 @@
import 'package:eatvio_app/features/cancel_plan_bottom_sheet/cubit/cancel_plan_cubit.dart';
import 'package:eatvio_app/features/cancel_plan_bottom_sheet/cubit/cancel_plan_state.dart';
import 'package:eatvio_app/features/cancel_plan_bottom_sheet/models/cancelation_model.dart';
import 'package:eatvio_app/features/cancel_plan_bottom_sheet/repository/cancel_plan_repository.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:mocktail/mocktail.dart';
import 'cancel_plan_cubit_test.mocks.dart';
class MockCancelPlanRepository extends Mock implements CancelPlanRepository {}
@GenerateNiceMocks([MockSpec<CancelPlanRepository>()])
void main() {
group('CancelPlanCubit', () {
CancelPlanCubit? cubit;
late CancelPlanCubit cubit;
late MockCancelPlanRepository mockRepository;
setUp(() {
mockRepository = MockCancelPlanRepository();
});
tearDown(() async {
if (cubit != null && !cubit!.isClosed) {
await cubit!.close();
cubit = null;
}
});
test('начальное состояние - пустое', () {
cubit = CancelPlanCubit(cancelPlanRepository: mockRepository);
expect(cubit!.state, isA<CancelPlanState>());
});
test('cancelChosenPlan - успешная отмена плана без причины', () async {
cubit = CancelPlanCubit(cancelPlanRepository: mockRepository);
when(mockRepository.cancelChosenPlan(
id: 1,
body: anyNamed('body'),
)).thenAnswer((_) async => {});
final result = await cubit!.cancelChosenPlan(id: 1);
expect(result, isTrue);
verify(mockRepository.cancelChosenPlan(id: 1, body: null)).called(1);
tearDown(() {
cubit.close();
});
test('cancelChosenPlan - успешная отмена плана с причиной', () async {
cubit = CancelPlanCubit(cancelPlanRepository: mockRepository);
when(mockRepository.cancelChosenPlan(
id: anyNamed('id'),
body: anyNamed('body'),
)).thenAnswer((_) async => {});
final result = await cubit!.cancelChosenPlan(
id: 1,
reason: 'Test reason',
price: 1000,
);
expect(result, isTrue);
verify(mockRepository.cancelChosenPlan(
id: 1,
body: anyNamed('body'),
)).called(1);
test('начальное состояние - CancelPlanState', () {
expect(cubit.state, isA<CancelPlanState>());
});
test('cancelChosenPlan - обработка ошибки', () async {
cubit = CancelPlanCubit(cancelPlanRepository: mockRepository);
test('cancelChosenPlan - успешная отмена без причины', () async {
const planId = 1;
when(mockRepository.cancelChosenPlan(
id: anyNamed('id'),
body: anyNamed('body'),
)).thenAnswer((_) async {
throw Exception('Ошибка отмены');
});
when(() => mockRepository.cancelChosenPlan(id: planId, body: null))
.thenAnswer((_) async => {});
final result = await cubit!.cancelChosenPlan(id: 1);
final result = await cubit.cancelChosenPlan(id: planId);
expect(result, isFalse);
expect(result, true);
verify(() => mockRepository.cancelChosenPlan(id: planId, body: null)).called(1);
});
test('cancelChosenPlan - успешная отмена с причиной и ценой', () async {
const planId = 1;
const reason = 'Test reason';
const price = 1000;
final body = CancelationModel(description: reason, price: price);
when(() => mockRepository.cancelChosenPlan(id: planId, body: body))
.thenAnswer((_) async => {});
final result = await cubit.cancelChosenPlan(id: planId, reason: reason, price: price);
expect(result, true);
verify(() => mockRepository.cancelChosenPlan(id: planId, body: body)).called(1);
});
test('cancelChosenPlan - возвращает false при ошибке', () async {
const planId = 1;
when(() => mockRepository.cancelChosenPlan(id: planId, body: null))
.thenThrow(Exception('Error'));
final result = await cubit.cancelChosenPlan(id: planId);
expect(result, false);
});
test('cancelChosenPlan - не создает body если reason или price null', () async {
const planId = 1;
when(() => mockRepository.cancelChosenPlan(id: planId, body: null))
.thenAnswer((_) async => {});
// Только reason
await cubit.cancelChosenPlan(id: planId, reason: 'reason');
verify(() => mockRepository.cancelChosenPlan(id: planId, body: null)).called(1);
// Только price
await cubit.cancelChosenPlan(id: planId, price: 100);
verify(() => mockRepository.cancelChosenPlan(id: planId, body: null)).called(1);
});
});
}

View File

@@ -3,27 +3,28 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
group('CancelationModel', () {
test('создает CancelationModel с правильными значениями', () {
final model = CancelationModel(
description: 'Test reason',
price: 1000,
);
test('создает экземпляр с description и price', () {
final model = CancelationModel(description: 'Test reason', price: 1000);
expect(model.description, 'Test reason');
expect(model.price, 1000);
});
test('fromJson создает CancelationModel из JSON', () {
final json = {
'description': 'Test reason',
'price': 1000,
};
test('fromJson создает модель из JSON', () {
final json = {'description': 'Test reason', 'price': 1000};
final model = CancelationModel.fromJson(json);
expect(model.description, 'Test reason');
expect(model.price, 1000);
});
test('toJson преобразует модель в JSON', () {
final model = CancelationModel(description: 'Test reason', price: 1000);
final json = model.toJson();
expect(json['description'], 'Test reason');
expect(json['price'], 1000);
});
});
}