import 'package:eatvio_app/features/consultant/become_consultant/repositories/consultant_repository.dart'; import 'package:eatvio_app/features/consultations/repositories/consultations_repository.dart'; import 'package:eatvio_app/features/profile/repositories/profile_repository.dart'; import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_cubit.dart'; import 'package:eatvio_app/features/settings/presentation/bloc/settings_cubit/settings_state.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 '../../../../fixtures/settings_fixtures.dart'; import 'settings_cubit_test.mocks.dart'; @GenerateNiceMocks([ MockSpec(), MockSpec(), MockSpec(), MockSpec(), ]) void main() { group('SettingsCubit', () { SettingsCubit? settingsCubit; late MockProfileRepository mockProfileRepository; late MockSettingsRepository mockSettingsRepository; late MockConsultantRepository mockConsultantRepository; late MockConsultationsRepository mockConsultationsRepository; setUp(() { mockProfileRepository = MockProfileRepository(); mockSettingsRepository = MockSettingsRepository(); mockConsultantRepository = MockConsultantRepository(); mockConsultationsRepository = MockConsultationsRepository(); }); tearDown(() async { if (settingsCubit != null && !settingsCubit!.isClosed) { await Future.delayed(const Duration(milliseconds: 100)); settingsCubit!.close(); settingsCubit = null; } }); test('начальное состояние - loading', () { settingsCubit = SettingsCubit( profileRepository: mockProfileRepository, settingsRepository: mockSettingsRepository, consultantRepository: mockConsultantRepository, consultationsRepository: mockConsultationsRepository, ); expect(settingsCubit!.state, const SettingsState.loading()); }); test('init - успешно инициализирует состояние', () async { settingsCubit = SettingsCubit( profileRepository: mockProfileRepository, settingsRepository: mockSettingsRepository, consultantRepository: mockConsultantRepository, consultationsRepository: mockConsultationsRepository, ); when(mockProfileRepository.getMyProfile()) .thenAnswer((_) async => SettingsFixtures.profileModel()); when(mockConsultantRepository.getMyRequestStatus(any)) .thenThrow(Exception('Not found')); when(mockConsultationsRepository.getUserPurchases(any, any)) .thenAnswer((_) async => []); when(mockSettingsRepository.getOAuthAccounts()) .thenAnswer((_) async => SettingsFixtures.oauthAccountsResponseModel()); when(mockSettingsRepository.getProfileSettings()) .thenAnswer((_) async => SettingsFixtures.profileSettingsModel()); when(mockProfileRepository.getMyProfileDetails()) .thenAnswer((_) async => SettingsFixtures.profileDetailsModel()); await settingsCubit!.init(); await Future.delayed(const Duration(milliseconds: 100)); expect(settingsCubit!.state, isA()); final loadedState = settingsCubit!.state as SettingsStateLoaded; expect(loadedState.profile.id, SettingsFixtures.profileModel().id); expect(loadedState.profileSettings.isMoodFillable, true); }); test('init - обрабатывает ошибку при загрузке настроек', () async { settingsCubit = SettingsCubit( profileRepository: mockProfileRepository, settingsRepository: mockSettingsRepository, consultantRepository: mockConsultantRepository, consultationsRepository: mockConsultationsRepository, ); // Ошибка происходит при загрузке настроек профиля (внутри try-catch блока) when(mockProfileRepository.getMyProfile()) .thenAnswer((_) async => SettingsFixtures.profileModel()); when(mockConsultantRepository.getMyRequestStatus(any)) .thenThrow(Exception('Not found')); when(mockConsultationsRepository.getUserPurchases(any, any)) .thenAnswer((_) async => []); when(mockSettingsRepository.getOAuthAccounts()) .thenAnswer((_) async => SettingsFixtures.oauthAccountsResponseModel()); when(mockSettingsRepository.getProfileSettings()) .thenThrow(Exception('Ошибка загрузки настроек')); await settingsCubit!.init(); await Future.delayed(const Duration(milliseconds: 200)); expect(settingsCubit!.state, isA()); final errorState = settingsCubit!.state as SettingsStateError; expect(errorState.errorMessage, contains('Ошибка загрузки настроек')); }); test('updateProfileDetails - обновляет детали профиля', () async { settingsCubit = SettingsCubit( profileRepository: mockProfileRepository, settingsRepository: mockSettingsRepository, consultantRepository: mockConsultantRepository, consultationsRepository: mockConsultationsRepository, ); when(mockProfileRepository.getMyProfile()) .thenAnswer((_) async => SettingsFixtures.profileModel()); when(mockConsultantRepository.getMyRequestStatus(any)) .thenThrow(Exception('Not found')); when(mockConsultationsRepository.getUserPurchases(any, any)) .thenAnswer((_) async => []); when(mockSettingsRepository.getOAuthAccounts()) .thenAnswer((_) async => SettingsFixtures.oauthAccountsResponseModel()); when(mockSettingsRepository.getProfileSettings()) .thenAnswer((_) async => SettingsFixtures.profileSettingsModel()); when(mockProfileRepository.getMyProfileDetails()) .thenAnswer((_) async => SettingsFixtures.profileDetailsModel()); when(mockSettingsRepository.updateProfileDetails(profileDetailsModel: anyNamed('profileDetailsModel'))) .thenAnswer((_) async => SettingsFixtures.profileDetailsModel()); await settingsCubit!.init(); await Future.delayed(const Duration(milliseconds: 100)); await settingsCubit!.updateProfileDetails(profileDetailsModel: SettingsFixtures.profileDetailsModel()); await Future.delayed(const Duration(milliseconds: 100)); verify(mockSettingsRepository.updateProfileDetails(profileDetailsModel: anyNamed('profileDetailsModel'))).called(1); }); test('updateProfileSettings - обновляет настройки профиля', () async { settingsCubit = SettingsCubit( profileRepository: mockProfileRepository, settingsRepository: mockSettingsRepository, consultantRepository: mockConsultantRepository, consultationsRepository: mockConsultationsRepository, ); when(mockProfileRepository.getMyProfile()) .thenAnswer((_) async => SettingsFixtures.profileModel()); when(mockConsultantRepository.getMyRequestStatus(any)) .thenThrow(Exception('Not found')); when(mockConsultationsRepository.getUserPurchases(any, any)) .thenAnswer((_) async => []); when(mockSettingsRepository.getOAuthAccounts()) .thenAnswer((_) async => SettingsFixtures.oauthAccountsResponseModel()); when(mockSettingsRepository.getProfileSettings()) .thenAnswer((_) async => SettingsFixtures.profileSettingsModel()); when(mockProfileRepository.getMyProfileDetails()) .thenAnswer((_) async => SettingsFixtures.profileDetailsModel()); when(mockSettingsRepository.updateProfileSettings(profileSettingsModel: anyNamed('profileSettingsModel'))) .thenAnswer((_) async => SettingsFixtures.profileSettingsModel()); await settingsCubit!.init(); await Future.delayed(const Duration(milliseconds: 100)); await settingsCubit!.updateProfileSettings(profileSettingsModel: SettingsFixtures.profileSettingsModel()); await Future.delayed(const Duration(milliseconds: 100)); verify(mockSettingsRepository.updateProfileSettings(profileSettingsModel: anyNamed('profileSettingsModel'))).called(1); }); test('deleteAccount - удаляет аккаунт', () async { settingsCubit = SettingsCubit( profileRepository: mockProfileRepository, settingsRepository: mockSettingsRepository, consultantRepository: mockConsultantRepository, consultationsRepository: mockConsultationsRepository, ); when(mockProfileRepository.deleteAccount()) .thenAnswer((_) async => Future.value()); final result = await settingsCubit!.deleteAccount(); expect(result, true); verify(mockProfileRepository.deleteAccount()).called(1); }); test('deleteAccount - возвращает false при ошибке', () async { settingsCubit = SettingsCubit( profileRepository: mockProfileRepository, settingsRepository: mockSettingsRepository, consultantRepository: mockConsultantRepository, consultationsRepository: mockConsultationsRepository, ); when(mockProfileRepository.deleteAccount()) .thenThrow(Exception('Ошибка удаления')); final result = await settingsCubit!.deleteAccount(); expect(result, false); }); test('linkOAuthAccount - привязывает OAuth аккаунт', () async { settingsCubit = SettingsCubit( profileRepository: mockProfileRepository, settingsRepository: mockSettingsRepository, consultantRepository: mockConsultantRepository, consultationsRepository: mockConsultationsRepository, ); when(mockProfileRepository.getMyProfile()) .thenAnswer((_) async => SettingsFixtures.profileModel()); when(mockConsultantRepository.getMyRequestStatus(any)) .thenThrow(Exception('Not found')); when(mockConsultationsRepository.getUserPurchases(any, any)) .thenAnswer((_) async => []); when(mockSettingsRepository.getOAuthAccounts()) .thenAnswer((_) async => SettingsFixtures.oauthAccountsResponseModel()); when(mockSettingsRepository.getProfileSettings()) .thenAnswer((_) async => SettingsFixtures.profileSettingsModel()); when(mockProfileRepository.getMyProfileDetails()) .thenAnswer((_) async => SettingsFixtures.profileDetailsModel()); when(mockSettingsRepository.linkOAuthAccount(request: anyNamed('request'))) .thenAnswer((_) async => Future.value()); await settingsCubit!.init(); await Future.delayed(const Duration(milliseconds: 100)); await settingsCubit!.linkOAuthAccount( provider: 'vk', accessToken: 'access_token', refreshToken: 'refresh_token', ); await Future.delayed(const Duration(milliseconds: 100)); verify(mockSettingsRepository.linkOAuthAccount(request: anyNamed('request'))).called(1); }); test('unlinkOAuthAccount - отвязывает OAuth аккаунт', () async { settingsCubit = SettingsCubit( profileRepository: mockProfileRepository, settingsRepository: mockSettingsRepository, consultantRepository: mockConsultantRepository, consultationsRepository: mockConsultationsRepository, ); when(mockProfileRepository.getMyProfile()) .thenAnswer((_) async => SettingsFixtures.profileModel()); when(mockConsultantRepository.getMyRequestStatus(any)) .thenThrow(Exception('Not found')); when(mockConsultationsRepository.getUserPurchases(any, any)) .thenAnswer((_) async => []); when(mockSettingsRepository.getOAuthAccounts()) .thenAnswer((_) async => SettingsFixtures.oauthAccountsResponseModel()); when(mockSettingsRepository.getProfileSettings()) .thenAnswer((_) async => SettingsFixtures.profileSettingsModel()); when(mockProfileRepository.getMyProfileDetails()) .thenAnswer((_) async => SettingsFixtures.profileDetailsModel()); when(mockSettingsRepository.unlinkOAuthAccount(provider: anyNamed('provider'))) .thenAnswer((_) async => Future.value()); await settingsCubit!.init(); await Future.delayed(const Duration(milliseconds: 100)); await settingsCubit!.unlinkOAuthAccount(provider: 'vk'); await Future.delayed(const Duration(milliseconds: 100)); verify(mockSettingsRepository.unlinkOAuthAccount(provider: anyNamed('provider'))).called(1); }); }); }