Stabilize auth flow and profile images
This commit is contained in:
@@ -0,0 +1,297 @@
|
||||
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/features/auth/data/auth_session_store.dart';
|
||||
import 'package:tdc114plus/src/features/auth/domain/auth_models.dart';
|
||||
import 'package:tdc114plus/src/features/directory/data/profile_image_api_client.dart';
|
||||
import 'package:tdc114plus/src/features/directory/domain/employee.dart';
|
||||
|
||||
void main() {
|
||||
setUp(() {
|
||||
SharedPreferences.setMockInitialValues({});
|
||||
});
|
||||
|
||||
test('keeps explicit profileImageUrl without auth lookup', () async {
|
||||
var requestCount = 0;
|
||||
final client = ProfileImageApiClient(
|
||||
httpClient: MockClient((request) async {
|
||||
requestCount += 1;
|
||||
return http.Response('{}', 500);
|
||||
}),
|
||||
baseUri: Uri.parse('https://114-auth.hmac.kr'),
|
||||
sessionStore: const AuthSessionStore(),
|
||||
);
|
||||
|
||||
const employee = Employee(
|
||||
id: 'user-1',
|
||||
name: '강경훈',
|
||||
phoneNumber: '01012345678',
|
||||
email: 'khkang@samaneng.com',
|
||||
tenantId: 'tenant-1',
|
||||
tenantName: '삼안',
|
||||
tenantSlug: 'saman',
|
||||
profileImageUrl: 'https://cdn.example.test/khkang.jpg',
|
||||
);
|
||||
|
||||
final imageUrl = await client.resolveImageUrl(employee);
|
||||
|
||||
expect(imageUrl, 'https://cdn.example.test/khkang.jpg');
|
||||
expect(requestCount, 0);
|
||||
});
|
||||
|
||||
test('uses auth profile-image endpoint when explicit profile image is absent', () async {
|
||||
const store = AuthSessionStore();
|
||||
await store.save(
|
||||
PhoneLoginResponse(
|
||||
status: 'ok',
|
||||
token: 'app-session-token',
|
||||
expiresAt: DateTime.now().toUtc().add(const Duration(hours: 1)),
|
||||
user: const LoginUser(
|
||||
id: 'user-1',
|
||||
name: '강경훈',
|
||||
phoneNumber: '01012345678',
|
||||
tenantId: 'tenant-1',
|
||||
tenantName: '삼안',
|
||||
tenantSlug: 'saman',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final client = ProfileImageApiClient(
|
||||
httpClient: MockClient((request) async {
|
||||
expect(request.url.host, '114-auth.hmac.kr');
|
||||
expect(request.url.path, '/api/v1/profile-image');
|
||||
expect(request.url.queryParameters['comp'], 'SAMAN');
|
||||
expect(request.url.queryParameters['email'], 'khkang@samaneng.com');
|
||||
expect(request.headers['Authorization'], 'Bearer app-session-token');
|
||||
return http.Response(
|
||||
jsonEncode({
|
||||
'found': true,
|
||||
'source': 'BARON_UUID_R2',
|
||||
'imageUrl':
|
||||
'https://baroncs.co.kr/employee_img/bebb832c-052e-493d-b5a9-732518d67685.jpg',
|
||||
}),
|
||||
200,
|
||||
headers: {'content-type': 'application/json'},
|
||||
);
|
||||
}),
|
||||
baseUri: Uri.parse('https://114-auth.hmac.kr'),
|
||||
sessionStore: store,
|
||||
);
|
||||
|
||||
const employee = Employee(
|
||||
id: 'bebb832c-052e-493d-b5a9-732518d67685',
|
||||
name: '강경훈',
|
||||
phoneNumber: '01012345678',
|
||||
email: 'khkang@samaneng.com',
|
||||
tenantId: 'tenant-1',
|
||||
tenantName: '삼안',
|
||||
tenantSlug: 'saman',
|
||||
);
|
||||
|
||||
final imageUrl = await client.resolveImageUrl(employee);
|
||||
|
||||
expect(
|
||||
imageUrl,
|
||||
'https://baroncs.co.kr/employee_img/bebb832c-052e-493d-b5a9-732518d67685.jpg',
|
||||
);
|
||||
});
|
||||
|
||||
test('returns null when employee email is missing', () async {
|
||||
final client = ProfileImageApiClient(
|
||||
httpClient: MockClient((request) async {
|
||||
fail('auth lookup should not be sent without email');
|
||||
}),
|
||||
baseUri: Uri.parse('https://114-auth.hmac.kr'),
|
||||
sessionStore: const AuthSessionStore(),
|
||||
);
|
||||
|
||||
const employee = Employee(
|
||||
id: 'user-2',
|
||||
name: '직원',
|
||||
phoneNumber: '01000000000',
|
||||
tenantId: 'tenant-2',
|
||||
tenantName: '한맥',
|
||||
tenantSlug: 'hanmac',
|
||||
);
|
||||
|
||||
expect(await client.resolveImageUrl(employee), isNull);
|
||||
});
|
||||
|
||||
test('falls back to public uuid image when employee email is missing', () async {
|
||||
final client = ProfileImageApiClient(
|
||||
httpClient: MockClient((request) async {
|
||||
fail('auth lookup should not be sent without email');
|
||||
}),
|
||||
baseUri: Uri.parse('https://114-auth.hmac.kr'),
|
||||
sessionStore: const AuthSessionStore(),
|
||||
);
|
||||
|
||||
const employee = Employee(
|
||||
id: 'bebb832c-052e-493d-b5a9-732518d67685',
|
||||
name: '강경훈',
|
||||
phoneNumber: '01012345678',
|
||||
tenantId: 'tenant-1',
|
||||
tenantName: '삼안',
|
||||
tenantSlug: 'saman',
|
||||
);
|
||||
|
||||
expect(
|
||||
await client.resolveImageUrl(employee),
|
||||
'https://baroncs.co.kr/employee_img/bebb832c-052e-493d-b5a9-732518d67685.jpg',
|
||||
);
|
||||
});
|
||||
|
||||
test('allows auth lookup without company code when tenant mapping is unknown', () async {
|
||||
const store = AuthSessionStore();
|
||||
await store.save(
|
||||
PhoneLoginResponse(
|
||||
status: 'ok',
|
||||
token: 'app-session-token',
|
||||
expiresAt: DateTime.now().toUtc().add(const Duration(hours: 1)),
|
||||
user: const LoginUser(
|
||||
id: 'user-3',
|
||||
name: '직원',
|
||||
phoneNumber: '01011112222',
|
||||
tenantId: 'tenant-3',
|
||||
tenantName: 'Unknown',
|
||||
tenantSlug: 'unknown',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final client = ProfileImageApiClient(
|
||||
httpClient: MockClient((request) async {
|
||||
expect(request.url.queryParameters['comp'], isNull);
|
||||
expect(request.url.queryParameters['email'], 'person@example.com');
|
||||
return http.Response(
|
||||
jsonEncode({'found': false, 'source': 'DEFAULT'}),
|
||||
200,
|
||||
headers: {'content-type': 'application/json'},
|
||||
);
|
||||
}),
|
||||
baseUri: Uri.parse('https://114-auth.hmac.kr'),
|
||||
sessionStore: store,
|
||||
);
|
||||
|
||||
const employee = Employee(
|
||||
id: 'user-3',
|
||||
name: '직원',
|
||||
phoneNumber: '01011112222',
|
||||
email: 'person@example.com',
|
||||
tenantId: 'tenant-3',
|
||||
tenantName: 'Unknown',
|
||||
tenantSlug: 'unknown',
|
||||
);
|
||||
|
||||
expect(await client.resolveImageUrl(employee), isNull);
|
||||
});
|
||||
|
||||
test('falls back to public uuid image when auth lookup returns not found', () async {
|
||||
const store = AuthSessionStore();
|
||||
await store.save(
|
||||
PhoneLoginResponse(
|
||||
status: 'ok',
|
||||
token: 'app-session-token',
|
||||
expiresAt: DateTime.now().toUtc().add(const Duration(hours: 1)),
|
||||
user: const LoginUser(
|
||||
id: 'user-4',
|
||||
name: '강경훈',
|
||||
phoneNumber: '01012345678',
|
||||
tenantId: 'tenant-1',
|
||||
tenantName: '삼안',
|
||||
tenantSlug: 'saman',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final client = ProfileImageApiClient(
|
||||
httpClient: MockClient((request) async {
|
||||
return http.Response(
|
||||
jsonEncode({'found': false, 'source': 'DEFAULT'}),
|
||||
200,
|
||||
headers: {'content-type': 'application/json'},
|
||||
);
|
||||
}),
|
||||
baseUri: Uri.parse('https://114-auth.hmac.kr'),
|
||||
sessionStore: store,
|
||||
);
|
||||
|
||||
const employee = Employee(
|
||||
id: 'bebb832c-052e-493d-b5a9-732518d67685',
|
||||
name: '강경훈',
|
||||
phoneNumber: '01012345678',
|
||||
email: 'khkang@samaneng.com',
|
||||
tenantId: 'tenant-1',
|
||||
tenantName: '삼안',
|
||||
tenantSlug: 'saman',
|
||||
);
|
||||
|
||||
expect(
|
||||
await client.resolveImageUrl(employee),
|
||||
'https://baroncs.co.kr/employee_img/bebb832c-052e-493d-b5a9-732518d67685.jpg',
|
||||
);
|
||||
});
|
||||
|
||||
test('uses uuid fallback even when auth not-found result is cached', () async {
|
||||
const store = AuthSessionStore();
|
||||
await store.save(
|
||||
PhoneLoginResponse(
|
||||
status: 'ok',
|
||||
token: 'app-session-token',
|
||||
expiresAt: DateTime.now().toUtc().add(const Duration(hours: 1)),
|
||||
user: const LoginUser(
|
||||
id: 'user-5',
|
||||
name: '직원',
|
||||
phoneNumber: '01012345678',
|
||||
tenantId: 'tenant-1',
|
||||
tenantName: '삼안',
|
||||
tenantSlug: 'saman',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
var requestCount = 0;
|
||||
final client = ProfileImageApiClient(
|
||||
httpClient: MockClient((request) async {
|
||||
requestCount += 1;
|
||||
return http.Response(
|
||||
jsonEncode({'found': false, 'source': 'DEFAULT'}),
|
||||
200,
|
||||
headers: {'content-type': 'application/json'},
|
||||
);
|
||||
}),
|
||||
baseUri: Uri.parse('https://114-auth.hmac.kr'),
|
||||
sessionStore: store,
|
||||
);
|
||||
|
||||
const firstEmployee = Employee(
|
||||
id: 'legacy-user-id',
|
||||
name: '직원',
|
||||
phoneNumber: '01012345678',
|
||||
email: 'cached-null@example.com',
|
||||
tenantId: 'tenant-1',
|
||||
tenantName: '삼안',
|
||||
tenantSlug: 'saman',
|
||||
);
|
||||
const secondEmployee = Employee(
|
||||
id: 'bebb832c-052e-493d-b5a9-732518d67685',
|
||||
name: '직원',
|
||||
phoneNumber: '01012345678',
|
||||
email: 'cached-null@example.com',
|
||||
tenantId: 'tenant-1',
|
||||
tenantName: '삼안',
|
||||
tenantSlug: 'saman',
|
||||
);
|
||||
|
||||
expect(await client.resolveImageUrl(firstEmployee), isNull);
|
||||
expect(
|
||||
await client.resolveImageUrl(secondEmployee),
|
||||
'https://baroncs.co.kr/employee_img/bebb832c-052e-493d-b5a9-732518d67685.jpg',
|
||||
);
|
||||
expect(requestCount, 1);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user