feat(app): refactoring of sentry using, feat(become_consultant): fixed possible infinite loading, feat(push_notifications): fixed push navigation from paid plan push

This commit is contained in:
misha
2026-04-07 10:05:11 +03:00
parent b6b13b1db5
commit aac085def4
133 changed files with 2344 additions and 2456 deletions

View File

@@ -379,25 +379,22 @@ void main() {
),
).thenThrow(Exception('Ошибка подтверждения'));
expect(
() => oauthCubit!.confirmOAuthVerification(
provider: 'google',
accessToken: 'access_token',
refreshToken: 'refresh_token',
clientId: 'client_id',
id: 'id',
email: 'test@example.com',
phone: null,
code: '123456',
verificationType: 'email',
firstName: 'Test',
lastName: 'User',
dateOfBirth: '2000-01-01',
gender: 'male',
weight: 70,
height: 175,
),
throwsException,
await oauthCubit!.confirmOAuthVerification(
provider: 'google',
accessToken: 'access_token',
refreshToken: 'refresh_token',
clientId: 'client_id',
id: 'id',
email: 'test@example.com',
phone: null,
code: '123456',
verificationType: 'email',
firstName: 'Test',
lastName: 'User',
dateOfBirth: '2000-01-01',
gender: 'male',
weight: 70,
height: 175,
);
await Future.delayed(const Duration(milliseconds: 100));

View File

@@ -21,7 +21,7 @@ void main() {
mockResetPasswordService = MockResetPasswordService();
resetPasswordRepository = ResetPasswordRepository(
resetPasswordService: mockResetPasswordService,
);
);
});
test('sendEmailCodeForPasswordChange - успешная отправка кода (200)', () async {

View File

@@ -24,74 +24,54 @@ void main() {
test('getProductByBarcode - возвращает успешный результат (200)', () async {
const barcode = '1234567890123';
final productData = {'GTIN': barcode, 'Описание (ru)': 'Test Product'};
final response = Response(
final response = Response<Map<String, dynamic>>(
data: productData,
statusCode: 200,
requestOptions: RequestOptions(path: '/api/gsone/barcode/$barcode'),
);
when(mockDio.get('/api/gsone/barcode/$barcode')).thenAnswer((_) async => response);
when(mockDio.get<Map<String, dynamic>>(any, options: anyNamed('options'))).thenAnswer((_) async => response);
final result = await repository.getProductByBarcode(barcode);
expect(result.type, BarcodeResultType.success);
expect(result.product, isNotNull);
expect(result.product!.description, 'Test Product');
verify(mockDio.get('/api/gsone/barcode/$barcode')).called(1);
verify(mockDio.get<Map<String, dynamic>>(any, options: anyNamed('options'))).called(1);
});
test('getProductByBarcode - возвращает статус обработки (202)', () async {
const barcode = '1234567890123';
final taskData = {'task_id': 'task-123', 'status': 'processing'};
final response = Response(
final response = Response<Map<String, dynamic>>(
data: taskData,
statusCode: 202,
requestOptions: RequestOptions(path: '/api/gsone/barcode/$barcode'),
);
when(mockDio.get('/api/gsone/barcode/$barcode')).thenAnswer((_) async => response);
when(mockDio.get<Map<String, dynamic>>(any, options: anyNamed('options'))).thenAnswer((_) async => response);
final result = await repository.getProductByBarcode(barcode);
expect(result.type, BarcodeResultType.processing);
expect(result.taskId, equals('task-123'));
verify(mockDio.get('/api/gsone/barcode/$barcode')).called(1);
verify(mockDio.get<Map<String, dynamic>>(any, options: anyNamed('options'))).called(1);
});
test('getProductByBarcode - обрабатывает DioException с 202 статусом', () async {
test('getProductByBarcode - пробрасывает DioException при нестандартном ответе', () async {
const barcode = '1234567890123';
final taskData = {'task_id': 'task-456', 'status': 'processing'};
final dioException = DioException(
final response = Response<Map<String, dynamic>>(
data: {'error': 'Not found'},
statusCode: 404,
requestOptions: RequestOptions(path: '/api/gsone/barcode/$barcode'),
response: Response(
data: taskData,
statusCode: 202,
requestOptions: RequestOptions(path: '/api/gsone/barcode/$barcode'),
),
);
when(mockDio.get('/api/gsone/barcode/$barcode')).thenThrow(dioException);
when(mockDio.get<Map<String, dynamic>>(any, options: anyNamed('options'))).thenAnswer((_) async => response);
final result = await repository.getProductByBarcode(barcode);
expect(result.type, BarcodeResultType.processing);
expect(result.taskId, equals('task-456'));
});
test('getProductByBarcode - пробрасывает исключение при другой ошибке', () async {
const barcode = '1234567890123';
final dioException = DioException(
requestOptions: RequestOptions(path: '/api/gsone/barcode/$barcode'),
response: Response(
data: {'error': 'Not found'},
statusCode: 404,
requestOptions: RequestOptions(path: '/api/gsone/barcode/$barcode'),
),
await expectLater(
repository.getProductByBarcode(barcode),
throwsA(isA<DioException>()),
);
when(mockDio.get('/api/gsone/barcode/$barcode')).thenThrow(dioException);
expect(() => repository.getProductByBarcode(barcode), throwsException);
});
test('getTaskStatus - возвращает completed статус', () async {

View File

@@ -357,15 +357,16 @@ void main() {
verify(mockChatService.getChatByUserSlug(slug: slug)).called(1);
});
test('getChatByUserSlug - возвращает error при ошибке', () async {
test('getChatByUserSlug - пробрасывает исключение при ошибке сети', () async {
const slug = 'user-slug';
when(mockChatService.getChatByUserSlug(slug: slug))
.thenThrow(Exception('Network error'));
final result = await chatRepository.getChatByUserSlug(slug);
expect(result, 'error');
await expectLater(
chatRepository.getChatByUserSlug(slug),
throwsA(isA<Exception>()),
);
});
});
}

View File

@@ -1,75 +1,75 @@
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/glossary/services/glossary_service.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
class MockGlossaryService extends Mock implements GlossaryService {}
void main() {
group('GlossaryRepository', () {
late GlossaryRepository repository;
late MockGlossaryService mockService;
setUp(() {
mockService = MockGlossaryService();
repository = GlossaryRepository(glossaryService: mockService);
});
test('getGlossaryListByQuery - успешный запрос', () async {
const query = 'test';
final mockGlossaries = <GlossaryModel>[];
final mockPagination = GlossaryPaginationModel(glossariesList: mockGlossaries);
when(() => mockService.getGlossaryByQuery(query: query))
.thenAnswer((_) async => mockPagination);
final result = await repository.getGlossaryListByQuery(query);
expect(result, mockGlossaries);
verify(() => mockService.getGlossaryByQuery(query: query)).called(1);
});
test('getGlossaryListByQuery - пробрасывает ошибку', () async {
const query = 'test';
when(() => mockService.getGlossaryByQuery(query: query))
.thenThrow(Exception('Error'));
expect(() => repository.getGlossaryListByQuery(query), throwsException);
});
});
}
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/glossary/services/glossary_service.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
class MockGlossaryService extends Mock implements GlossaryService {}
void main() {
group('GlossaryRepository', () {
late GlossaryRepository repository;
late MockGlossaryService mockService;
setUp(() {
mockService = MockGlossaryService();
repository = GlossaryRepository(glossaryService: mockService);
});
test('getGlossaryListByQuery - успешный запрос', () async {
const query = 'test';
final mockGlossaries = <GlossaryModel>[];
final mockPagination = GlossaryPaginationModel(glossariesList: mockGlossaries);
when(() => mockService.getGlossaryByQuery(query: query))
.thenAnswer((_) async => mockPagination);
final result = await repository.getGlossaryListByQuery(query);
expect(result, mockGlossaries);
verify(() => mockService.getGlossaryByQuery(query: query)).called(1);
});
test('getGlossaryListByQuery - пробрасывает ошибку', () async {
const query = 'test';
when(() => mockService.getGlossaryByQuery(query: query))
.thenThrow(Exception('Error'));
expect(() => repository.getGlossaryListByQuery(query), throwsException);
});
});
}

View File

@@ -17,7 +17,7 @@ void main() {
mockBlockedUserService = MockBlockedUserService();
blockedUsersRepository = BlockedUsersRepository(
blockedUserService: mockBlockedUserService,
);
);
});
test('getBlockedUsers - возвращает список заблокированных пользователей', () async {

View File

@@ -18,7 +18,7 @@ void main() {
mockService = MockPersonalDietSuggestionService();
repository = PersonalDietSuggestionRepository(
personalDietSuggestionService: mockService,
);
);
});
test('getConsultationWithPersonalDiets - успешная загрузка консультаций', () async {

View File

@@ -1,3 +1,4 @@
import 'package:easy_debounce/easy_debounce.dart';
import 'package:eatvio_app/core/models/pagination_model.dart';
import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart';
import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart';
@@ -59,9 +60,12 @@ void main() {
});
tearDown(() async {
EasyDebounce.cancel('loadPlans');
EasyDebounce.cancel('like_plan');
EasyDebounce.cancel('add_or_remove_plan_from_favorite');
if (plansCubit != null && !plansCubit!.isClosed) {
await Future.delayed(const Duration(milliseconds: 100));
plansCubit!.close();
await plansCubit!.close();
plansCubit = null;
}
});

View File

@@ -143,7 +143,7 @@ void main() {
when(mockProfileRepository.getProfileBySlug('test-user')).thenThrow(Exception('Ошибка загрузки'));
expect(() => profileCubit!.getProfileBySlug('test-user'), throwsException);
await profileCubit!.getProfileBySlug('test-user');
final state = profileCubit!.state;
expect(state, isA<ProfileStateError>());

View File

@@ -280,9 +280,8 @@ void main() {
when(mockService.tryVerifyEmailByCode(code: '{"code": "$code"}')).thenAnswer((_) async => Future<void>.value());
final result = await repository.tryVerifyEmailByCode(code);
await repository.tryVerifyEmailByCode(code);
expect(result, isTrue);
verify(mockService.tryVerifyEmailByCode(code: '{"code": "$code"}')).called(1);
});
@@ -291,9 +290,10 @@ void main() {
when(mockService.tryVerifyEmailByCode(code: '{"code": "$code"}')).thenThrow(Exception('Invalid code'));
final result = await repository.tryVerifyEmailByCode(code);
expect(result, isFalse);
await expectLater(
repository.tryVerifyEmailByCode(code),
throwsA(isA<Exception>()),
);
});
test('deleteAccount - удаляет аккаунт', () async {

View File

@@ -228,7 +228,8 @@ void main() {
final result = await myRecipesCubit!.getRecipeById('test-recipe');
expect(result, isA<Recipe>());
expect(result.id, 1);
expect(result, isNotNull);
expect(result!.id, 1);
expect(result.slug, 'test-recipe');
verify(mockAboutRecipeRepository.getRecipe('test-recipe')).called(1);
});

View File

@@ -139,13 +139,14 @@ void main() {
expect(cubit.state.sheet.responseBody, '{"locations": ["London, UK"]}');
});
test('getLocationsByQuery rethrows exception on error', () async {
test('getLocationsByQuery returns empty list on error', () async {
const query = 'Invalid';
final exception = Exception('Network error');
when(() => mockRepository.getLocationsListByQuery(query)).thenThrow(exception);
expect(() => cubit.getLocationsByQuery(query), throwsException);
final result = await cubit.getLocationsByQuery(query);
expect(result, isEmpty);
});
test('getLocationsByCoordinates returns list of locations', () async {
@@ -176,14 +177,15 @@ void main() {
expect(cubit.state.sheet.responseBody, '{"locations": ["London, UK"]}');
});
test('getLocationsByCoordinates rethrows exception on error', () async {
test('getLocationsByCoordinates returns empty list on error', () async {
const latitude = 'invalid';
const longitude = 'invalid';
final exception = Exception('Invalid coordinates');
when(() => mockRepository.getLocationsListByCoordinates(latitude, longitude)).thenThrow(exception);
expect(() => cubit.getLocationsByCoordinates(latitude, longitude), throwsException);
final result = await cubit.getLocationsByCoordinates(latitude, longitude);
expect(result, isEmpty);
});
test('getLocationsByQuery handles empty query', () async {

View File

@@ -140,7 +140,7 @@ void main() {
when(mockRepository.sendEmailCode())
.thenAnswer((_) async => {});
when(mockRepository.tryVerifyEmailByCode('wrong'))
.thenAnswer((_) async => false);
.thenThrow(Exception('Неверный код'));
await cubit!.sendEmailCode();
await cubit!.tryVerify('wrong');

View File

@@ -145,7 +145,10 @@ void main() {
when(() => mockService.register(sheet: any(named: 'sheet')))
.thenThrow(dioException);
expect(() => repository.tryRegister(sheet), throwsA(isA<String>()));
await expectLater(
repository.tryRegister(sheet),
throwsA(isA<DioException>()),
);
});
test('getLocationsListByQuery - возвращает LocationModel', () async {