import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:social_app/features/auth/data/auth_api.dart'; import 'package:social_app/features/auth/data/auth_repository_impl.dart'; import 'package:social_app/features/auth/data/models/signup_request.dart'; import 'package:social_app/features/auth/data/models/login_request.dart'; import 'package:social_app/features/auth/data/models/auth_response.dart'; import 'package:social_app/core/storage/token_storage.dart'; class MockAuthApi extends Mock implements AuthApi {} class MockTokenStorage extends Mock implements TokenStorage {} void main() { late AuthRepositoryImpl repository; late MockAuthApi mockApi; late MockTokenStorage mockStorage; setUp(() { mockApi = MockAuthApi(); mockStorage = MockTokenStorage(); repository = AuthRepositoryImpl(api: mockApi, tokenStorage: mockStorage); registerFallbackValue(const OtpSendRequest(phone: '')); registerFallbackValue(const LoginRequest(phone: '', token: '')); registerFallbackValue(const LogoutRequest(refreshToken: '')); registerFallbackValue(const RefreshRequest(refreshToken: '')); }); group('AuthRepositoryImpl', () { test('sendOtp calls api', () async { when(() => mockApi.sendOtp(any())).thenAnswer((_) async {}); await repository.sendOtp('+8613812345678'); verify(() => mockApi.sendOtp(any())).called(1); }); test('createPhoneSession calls api and saves tokens', () async { when(() => mockApi.createPhoneSession(any())).thenAnswer( (_) async => AuthResponse( accessToken: 'access_token', refreshToken: 'refresh_token', expiresIn: 3600, tokenType: 'bearer', user: const AuthUser(id: '123', phone: '+8613812345678'), ), ); when( () => mockStorage.saveTokens( access: any(named: 'access'), refresh: any(named: 'refresh'), ), ).thenAnswer((_) async {}); final result = await repository.createPhoneSession( phone: '+8613812345678', token: '123456', ); expect(result.accessToken, 'access_token'); verify( () => mockStorage.saveTokens( access: 'access_token', refresh: 'refresh_token', ), ).called(1); }); test( 'deleteSession calls api with refresh token and clears storage', () async { when( () => mockStorage.getRefreshToken(), ).thenAnswer((_) async => 'refresh_token'); when(() => mockApi.deleteSession(any())).thenAnswer((_) async {}); when(() => mockStorage.clear()).thenAnswer((_) async {}); await repository.deleteSession(); verify(() => mockApi.deleteSession(any())).called(1); verify(() => mockStorage.clear()).called(1); }, ); test( 'clearSessionLocalOnly clears local tokens without api revoke', () async { when(() => mockStorage.clear()).thenAnswer((_) async {}); await repository.clearSessionLocalOnly(); verify(() => mockStorage.clear()).called(1); verifyNever(() => mockApi.deleteSession(any())); }, ); test('refreshSession saves new tokens', () async { when(() => mockApi.refreshSession(any())).thenAnswer( (_) async => AuthResponse( accessToken: 'new_access', refreshToken: 'new_refresh', expiresIn: 3600, tokenType: 'bearer', user: const AuthUser(id: '123', phone: '+8613812345678'), ), ); when( () => mockStorage.saveTokens( access: any(named: 'access'), refresh: any(named: 'refresh'), ), ).thenAnswer((_) async {}); final result = await repository.refreshSession('old_refresh'); expect(result.accessToken, 'new_access'); verify( () => mockStorage.saveTokens( access: 'new_access', refresh: 'new_refresh', ), ).called(1); }); }); }