0661016827
- Replace Email+Password login with Phone+OTP flow - Remove RegisterCubit and registration screens (email verification) - Remove ResetPasswordCubit and reset password screens - Add phone normalization and international dial code support - Update LoginCubit with sendCode/resend cooldown logic - Add new widgets: phone prefix selector, confirm sheet - Update all auth API endpoints: /otp/send, /phone-session - Update form inputs: Email -> Phone with E.164 validation - Update tests for new auth flow
126 lines
3.9 KiB
Dart
126 lines
3.9 KiB
Dart
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);
|
|
});
|
|
});
|
|
}
|