import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:get_it/get_it.dart'; import 'package:go_router/go_router.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart' as lucide; import 'package:shadcn_ui/shadcn_ui.dart'; import 'package:superport_v2/core/constants/app_sections.dart'; import 'package:superport_v2/core/permissions/permission_manager.dart'; import 'package:superport_v2/core/theme/superport_shad_theme.dart'; import 'package:superport_v2/core/theme/theme_controller.dart'; import 'package:superport_v2/core/services/token_storage.dart'; import 'package:superport_v2/features/auth/application/auth_service.dart'; import 'package:superport_v2/features/auth/domain/entities/auth_permission.dart'; import 'package:superport_v2/features/auth/domain/entities/auth_session.dart'; import 'package:superport_v2/features/auth/domain/entities/authenticated_user.dart'; import 'package:superport_v2/features/auth/domain/entities/login_request.dart'; import 'package:superport_v2/features/auth/domain/repositories/auth_repository.dart'; import 'package:superport_v2/widgets/app_shell.dart'; void main() { setUp(() { GetIt.I.reset(); }); testWidgets('계정 버튼을 누르면 계정 정보 다이얼로그가 표시된다', (tester) async { final session = _buildSession(); final authService = _createAuthService(session); GetIt.I.registerSingleton(authService); addTearDown(authService.dispose); await authService.login( const LoginRequest(identifier: 'user@example.com', password: 'secret'), ); await _pumpAppShell(tester); await tester.tap(find.byIcon(lucide.LucideIcons.userRound)); await tester.pumpAndSettle(); expect(find.text('계정 정보'), findsOneWidget); expect(find.text('김승인'), findsWidgets); expect(find.text('E2025001'), findsOneWidget); expect(find.text('물류팀'), findsOneWidget); expect(find.textContaining('/approvals'), findsOneWidget); }); testWidgets('다이얼로그에서 로그아웃을 누르면 세션이 초기화되고 로그인 화면으로 이동한다', (tester) async { final session = _buildSession(); final authService = _createAuthService(session); GetIt.I.registerSingleton(authService); addTearDown(authService.dispose); await authService.login( const LoginRequest(identifier: 'user@example.com', password: 'secret'), ); await _pumpAppShell(tester); expect(authService.session, isNotNull); await tester.tap(find.byIcon(lucide.LucideIcons.userRound)); await tester.pumpAndSettle(); await tester.tap(find.text('로그아웃')); await tester.pumpAndSettle(); expect(authService.session, isNull); expect(find.text('로그인 페이지'), findsOneWidget); }); } Future _pumpAppShell(WidgetTester tester) async { final themeController = ThemeController(); final permissionManager = PermissionManager(); final router = GoRouter( initialLocation: dashboardRoutePath, routes: [ GoRoute( path: loginRoutePath, builder: (context, state) => const _LoginPlaceholder(), ), ShellRoute( builder: (context, state, child) => AppShell(currentLocation: state.uri.toString(), child: child), routes: [ GoRoute( path: dashboardRoutePath, builder: (context, state) => const _DashboardPlaceholder(), ), ], ), ], ); addTearDown(themeController.dispose); addTearDown(permissionManager.dispose); addTearDown(router.dispose); await tester.pumpWidget( PermissionScope( manager: permissionManager, child: ThemeControllerScope( controller: themeController, child: ShadApp.router( routerConfig: router, theme: SuperportShadTheme.light(), darkTheme: SuperportShadTheme.dark(), debugShowCheckedModeBanner: false, ), ), ), ); await tester.pumpAndSettle(); } AuthSession _buildSession() { return AuthSession( accessToken: 'access-token', refreshToken: 'refresh-token', expiresAt: DateTime.parse('2025-10-21T09:00:00Z'), user: const AuthenticatedUser( id: 7, name: '김승인', employeeNo: 'E2025001', email: 'approver@example.com', primaryGroupId: 3, primaryGroupName: '물류팀', ), permissions: const [ AuthPermission(resource: '/dashboard', actions: ['read']), AuthPermission(resource: '/approvals', actions: ['read', 'update']), ], ); } AuthService _createAuthService(AuthSession session) { final repository = _FakeAuthRepository(session); final tokenStorage = _MemoryTokenStorage(); return AuthService(repository: repository, tokenStorage: tokenStorage); } class _FakeAuthRepository implements AuthRepository { _FakeAuthRepository(this.session); final AuthSession session; @override Future login(LoginRequest request) async => session; @override Future refresh(String refreshToken) async => session; } class _MemoryTokenStorage implements TokenStorage { String? _access; String? _refresh; @override Future clear() async { _access = null; _refresh = null; } @override Future readAccessToken() async => _access; @override Future readRefreshToken() async => _refresh; @override Future writeAccessToken(String? token) async { _access = token; } @override Future writeRefreshToken(String? token) async { _refresh = token; } } class _DashboardPlaceholder extends StatelessWidget { const _DashboardPlaceholder(); @override Widget build(BuildContext context) { return const Scaffold(body: Center(child: Text('대시보드 본문'))); } } class _LoginPlaceholder extends StatelessWidget { const _LoginPlaceholder(); @override Widget build(BuildContext context) { return const Scaffold(body: Center(child: Text('로그인 페이지'))); } }