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:shadcn_ui/shadcn_ui.dart'; import 'package:superport_v2/core/common/models/paginated_result.dart'; import 'package:superport_v2/core/config/environment.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/features/login/presentation/pages/login_page.dart'; import 'package:superport_v2/features/masters/group/domain/entities/group.dart'; import 'package:superport_v2/features/masters/group/domain/repositories/group_repository.dart'; import 'package:superport_v2/features/masters/group_permission/domain/entities/group_permission.dart'; import 'package:superport_v2/features/masters/group_permission/domain/repositories/group_permission_repository.dart'; GoRouter _createTestRouter() { return GoRouter( initialLocation: loginRoutePath, routes: [ GoRoute( path: loginRoutePath, builder: (context, state) => const LoginPage(), ), GoRoute( path: dashboardRoutePath, builder: (context, state) => const _TestDashboardPage(), ), GoRoute( path: '/inventory/inbound', builder: (context, state) => const _PlaceholderPage(title: '입고 화면'), ), GoRoute( path: '/inventory/outbound', builder: (context, state) => const _PlaceholderPage(title: '출고 화면'), ), GoRoute( path: '/inventory/rental', builder: (context, state) => const _PlaceholderPage(title: '대여 화면'), ), ], ); } class _TestApp extends StatelessWidget { const _TestApp({required this.router}); final GoRouter router; @override Widget build(BuildContext context) { return PermissionScope( manager: PermissionManager(), child: ShadApp.router( routerConfig: router, debugShowCheckedModeBanner: false, theme: SuperportShadTheme.light(), darkTheme: SuperportShadTheme.dark(), ), ); } } class _TestDashboardPage extends StatelessWidget { const _TestDashboardPage(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('테스트 대시보드'), actions: [ IconButton( tooltip: '로그아웃', icon: const Icon(Icons.logout), onPressed: () => context.go(loginRoutePath), ), ], ), body: Padding( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ TextButton( onPressed: () => context.go('/inventory/inbound'), child: const Text('입고로 이동'), ), TextButton( onPressed: () => context.go('/inventory/outbound'), child: const Text('출고로 이동'), ), TextButton( onPressed: () => context.go('/inventory/rental'), child: const Text('대여로 이동'), ), ], ), ), ); } } class _PlaceholderPage extends StatelessWidget { const _PlaceholderPage({required this.title}); final String title; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(title)), body: Center( child: TextButton( onPressed: () => context.go(dashboardRoutePath), child: const Text('대시보드로 돌아가기'), ), ), ); } } class _StubGroupRepository implements GroupRepository { @override Future create(GroupInput input) { throw UnimplementedError(); } @override Future delete(int id) { throw UnimplementedError(); } @override Future> list({ int page = 1, int pageSize = 20, String? query, bool? isDefault, bool? isActive, bool includePermissions = false, bool includeEmployees = false, }) async { return PaginatedResult( items: [ Group( id: 1, groupName: '기본 그룹', description: '테스트', isDefault: true, isActive: true, ), ], page: 1, pageSize: 1, total: 1, ); } @override Future restore(int id) { throw UnimplementedError(); } @override Future update(int id, GroupInput input) { throw UnimplementedError(); } } class _StubGroupPermissionRepository implements GroupPermissionRepository { @override Future create(GroupPermissionInput input) { throw UnimplementedError(); } @override Future delete(int id) { throw UnimplementedError(); } @override Future> list({ int page = 1, int pageSize = 20, int? groupId, int? menuId, bool? isActive, bool includeDeleted = false, }) async { return PaginatedResult( items: [ GroupPermission( id: 1, group: GroupPermissionGroup(id: groupId ?? 1, groupName: '기본 그룹'), menu: GroupPermissionMenu( id: 10, menuCode: 'DASHBOARD', menuName: '대시보드', path: dashboardRoutePath, ), canCreate: true, canRead: true, canUpdate: true, canDelete: true, ), ], page: 1, pageSize: 1, total: 1, ); } @override Future restore(int id) { throw UnimplementedError(); } @override Future update(int id, GroupPermissionInput input) { throw UnimplementedError(); } } void main() { TestWidgetsFlutterBinding.ensureInitialized(); setUpAll(() async { await Environment.initialize(); }); Finder editableTextAt(int index) => find.byType(EditableText).at(index); testWidgets('사용자가 로그인 후 주요 화면을 탐색할 수 있다', (tester) async { final view = tester.view; view.physicalSize = const Size(1080, 720); view.devicePixelRatio = 1.0; addTearDown(() { view.resetPhysicalSize(); view.resetDevicePixelRatio(); }); await GetIt.I.reset(); GetIt.I.registerSingleton(_StubGroupRepository()); GetIt.I.registerSingleton( _StubGroupPermissionRepository(), ); addTearDown(() async => GetIt.I.reset()); final router = _createTestRouter(); await tester.pumpWidget(_TestApp(router: router)); await tester.pumpAndSettle(); expect(find.text('Superport v2 로그인'), findsOneWidget); await tester.enterText(editableTextAt(0), 'tester'); await tester.enterText(editableTextAt(1), 'password123'); await tester.tap(find.widgetWithText(ShadButton, '로그인')); await tester.pump(const Duration(milliseconds: 650)); await tester.pumpAndSettle(); expect(find.text('테스트 대시보드'), findsOneWidget); await tester.tap(find.widgetWithText(TextButton, '입고로 이동')); await tester.pumpAndSettle(); expect(find.text('입고 화면'), findsOneWidget); await tester.tap(find.widgetWithText(TextButton, '대시보드로 돌아가기')); await tester.pumpAndSettle(); expect(find.text('테스트 대시보드'), findsOneWidget); await tester.tap(find.widgetWithText(TextButton, '출고로 이동')); await tester.pumpAndSettle(); expect(find.text('출고 화면'), findsOneWidget); await tester.tap(find.widgetWithText(TextButton, '대시보드로 돌아가기')); await tester.pumpAndSettle(); await tester.tap(find.widgetWithText(TextButton, '대여로 이동')); await tester.pumpAndSettle(); expect(find.text('대여 화면'), findsOneWidget); await tester.tap(find.widgetWithText(TextButton, '대시보드로 돌아가기')); await tester.pumpAndSettle(); await tester.tap(find.byTooltip('로그아웃')); await tester.pumpAndSettle(); expect(find.text('Superport v2 로그인'), findsOneWidget); }); }