Files
tdc114plus/app/test/auth/auth_repository_test.dart

142 lines
4.4 KiB
Dart

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<ApiException>().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');
});
}