import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:dartz/dartz.dart'; import 'package:superport/data/models/auth/login_request.dart'; import 'package:superport/data/models/auth/login_response.dart'; import 'package:superport/data/models/auth/auth_user.dart'; import 'package:superport/core/errors/failures.dart'; import 'package:superport/data/models/auth/token_response.dart'; import '../../helpers/test_helpers.dart'; import 'package:superport/services/auth_service.dart'; import 'package:get_it/get_it.dart'; // Mock AuthService class MockAuthService extends Mock implements AuthService { @override Stream get authStateChanges => const Stream.empty(); } void main() { group('로그인 플로우 Integration 테스트', () { late MockAuthService mockAuthService; final getIt = GetIt.instance; setUp(() { setupTestGetIt(); mockAuthService = MockAuthService(); // Mock 서비스 등록 getIt.registerSingleton(mockAuthService); }); tearDown(() { getIt.reset(); }); test('성공적인 로그인 플로우 - 로그인 → 토큰 저장 → 사용자 정보 조회', () async { // Arrange const loginRequest = LoginRequest( email: 'admin@superport.kr', password: 'admin123!', ); final loginResponse = LoginResponse( accessToken: 'test_access_token', refreshToken: 'test_refresh_token', tokenType: 'Bearer', expiresIn: 3600, user: AuthUser( id: 1, username: 'admin', email: 'admin@superport.kr', name: '관리자', role: 'S', // S: 관리자 ), ); // Mock 설정 when(mockAuthService.login(loginRequest)) .thenAnswer((_) async => Right(loginResponse)); when(mockAuthService.getAccessToken()) .thenAnswer((_) async => 'test_access_token'); when(mockAuthService.getCurrentUser()) .thenAnswer((_) async => loginResponse.user); // Act - 로그인 final loginResult = await mockAuthService.login(loginRequest); // Assert - 로그인 성공 expect(loginResult.isRight(), true); loginResult.fold( (failure) => fail('로그인이 실패하면 안됩니다'), (response) { expect(response.accessToken, 'test_access_token'); expect(response.user.email, 'admin@superport.kr'); expect(response.user.role, 'S'); }, ); // Act - 토큰 조회 final savedToken = await mockAuthService.getAccessToken(); expect(savedToken, 'test_access_token'); // Act - 사용자 정보 조회 final currentUser = await mockAuthService.getCurrentUser(); expect(currentUser, isNotNull); expect(currentUser!.email, 'admin@superport.kr'); // Verify - 메서드 호출 확인 verify(mockAuthService.login(loginRequest)).called(1); verify(mockAuthService.getAccessToken()).called(1); verify(mockAuthService.getCurrentUser()).called(1); }); test('로그인 실패 플로우 - 잘못된 인증 정보', () async { // Arrange const loginRequest = LoginRequest( email: 'wrong@email.com', password: 'wrongpassword', ); // Mock 설정 when(mockAuthService.login(loginRequest)) .thenAnswer((_) async => Left( AuthenticationFailure( message: '이메일 또는 비밀번호가 올바르지 않습니다.', ), )); // Act final result = await mockAuthService.login(loginRequest); // Assert expect(result.isLeft(), true); result.fold( (failure) { expect(failure, isA()); expect(failure.message, contains('올바르지 않습니다')); }, (_) => fail('로그인이 성공하면 안됩니다'), ); }); test('로그아웃 플로우', () async { // Arrange - 먼저 로그인 상태 설정 when(mockAuthService.getAccessToken()) .thenAnswer((_) async => 'test_access_token'); when(mockAuthService.getCurrentUser()) .thenAnswer((_) async => AuthUser( id: 1, username: 'admin', email: 'admin@superport.kr', name: '관리자', role: 'S', )); // 로그인 상태 확인 expect(await mockAuthService.getAccessToken(), isNotNull); expect(await mockAuthService.getCurrentUser(), isNotNull); // Mock 설정 - 로그아웃 when(mockAuthService.logout()).thenAnswer((_) async => const Right(null)); // 로그아웃 후 상태 변경 when(mockAuthService.getAccessToken()) .thenAnswer((_) async => null); when(mockAuthService.getCurrentUser()) .thenAnswer((_) async => null); // Act - 로그아웃 await mockAuthService.logout(); // Assert - 로그아웃 확인 expect(await mockAuthService.getAccessToken(), isNull); expect(await mockAuthService.getCurrentUser(), isNull); // Verify verify(mockAuthService.logout()).called(1); }); test('토큰 갱신 플로우', () async { // Arrange const oldToken = 'old_access_token'; const newToken = 'new_access_token'; const refreshToken = 'test_refresh_token'; // Mock 설정 - 초기 토큰 when(mockAuthService.getAccessToken()) .thenAnswer((_) async => oldToken); // getRefreshToken 메서드가 AuthService에 없으므로 제거 // Mock 설정 - 토큰 갱신 when(mockAuthService.refreshToken()) .thenAnswer((_) async => Right( TokenResponse( accessToken: newToken, refreshToken: refreshToken, tokenType: 'Bearer', expiresIn: 3600, ), )); // 갱신 후 새 토큰 반환 when(mockAuthService.getAccessToken()) .thenAnswer((_) async => newToken); // Act final refreshResult = await mockAuthService.refreshToken(); // Assert expect(refreshResult.isRight(), true); refreshResult.fold( (failure) => fail('토큰 갱신이 실패하면 안됩니다'), (response) { expect(response.accessToken, newToken); }, ); // 갱신 후 토큰 확인 final currentToken = await mockAuthService.getAccessToken(); expect(currentToken, newToken); // Verify verify(mockAuthService.refreshToken()).called(1); }); }); }