import 'dart:convert'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; import 'package:http/testing.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tdc114plus/src/core/network/api_error.dart'; import 'package:tdc114plus/src/features/auth/data/auth_api_client.dart'; import 'package:tdc114plus/src/features/auth/data/auth_repository.dart'; import 'package:tdc114plus/src/features/auth/data/auth_session_store.dart'; void main() { setUp(() { SharedPreferences.setMockInitialValues({}); }); test('normalizes phone number and stores successful session', () async { final repository = RemoteAuthRepository( apiClient: AuthApiClient( httpClient: MockClient((request) async { expect(jsonDecode(request.body)['phoneNumber'], '01012345678'); return http.Response( jsonEncode({ 'status': 'ok', 'token': 'session-token', 'expiresAt': '2026-07-02T12:00:00Z', 'user': { 'id': 'user-uuid', 'name': 'User One', 'phoneNumber': '+821012345678', 'tenantId': 'tenant-uuid', 'tenantName': 'Hanmac', 'tenantSlug': 'hanmac', }, }), 200, ); }), baseUri: Uri.parse('https://sso.example.test'), ), sessionStore: const AuthSessionStore(), appVersion: '0.1.0', ); await repository.phoneLogin('010-1234-5678'); final session = await repository.loadSession(); expect(session?.token, 'session-token'); expect(session?.user.id, 'user-uuid'); }); test('rejects invalid phone number before calling API', () async { var called = false; final repository = RemoteAuthRepository( apiClient: AuthApiClient( httpClient: MockClient((request) async { called = true; return http.Response('{}', 200); }), baseUri: Uri.parse('https://sso.example.test'), ), sessionStore: const AuthSessionStore(), appVersion: '0.1.0', ); expect( () => repository.phoneLogin('123'), throwsA( isA().having( (error) => error.code, 'code', 'invalid_phone_number', ), ), ); expect(called, isFalse); }); test('normalizes phone number before requesting login link', () async { final repository = RemoteAuthRepository( apiClient: AuthApiClient( httpClient: MockClient((request) async { expect(request.url.path, '/api/v1/auth/link/init'); expect(jsonDecode(request.body)['phoneNumber'], '01012345678'); return http.Response( jsonEncode({ 'status': 'pending', 'pendingRef': 'pending-ref', 'expiresIn': 180, 'pollInterval': 3, 'resendAfter': 30, }), 200, ); }), baseUri: Uri.parse('https://sso.example.test'), ), sessionStore: const AuthSessionStore(), appVersion: '0.1.0', ); final response = await repository.requestPhoneLoginLink('010-1234-5678'); expect(response.pendingRef, 'pending-ref'); }); test('stores session when login link polling completes', () async { final repository = RemoteAuthRepository( apiClient: AuthApiClient( httpClient: MockClient((request) async { expect(request.url.path, '/api/v1/auth/link/poll'); return http.Response( jsonEncode({ 'status': 'ok', 'accessToken': 'session-token', 'expiresAt': '2026-07-02T12:00:00Z', 'user': { 'id': 'user-uuid', 'name': 'User One', 'phoneNumber': '+821012345678', 'tenantId': 'tenant-uuid', 'tenantName': 'Hanmac', 'tenantSlug': 'hanmac', }, }), 200, ); }), baseUri: Uri.parse('https://sso.example.test'), ), sessionStore: const AuthSessionStore(), appVersion: '0.1.0', ); final response = await repository.pollPhoneLoginLink('pending-ref'); final session = await repository.loadSession(); expect(response.session?.token, 'session-token'); expect(session?.token, 'session-token'); }); }