import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:provider/provider.dart'; import 'package:lanebow/screens/club/events_screen.dart'; import 'package:lanebow/services/auth_service.dart'; import 'package:lanebow/services/club_service.dart'; import 'package:lanebow/services/event_service.dart'; import 'package:lanebow/models/event_model.dart'; import 'package:lanebow/services/api_service.dart'; // Stub AuthService: 항상 토큰을 제공해 _loadEvents 내 initialize(token!) 경로가 실패하지 않도록 함 class StubAuthService extends AuthService { @override String? get token => 'test-token'; } // Stub EventService: 네트워크 호출 없이 createEventsFromFile만 성공 처리 class StubEventService extends EventService { StubEventService() : super.forTest(ApiService()); @override Future> createEventsFromFile(List> eventsData) async { // 입력된 맵을 Event로 변환하여 반환 (필수 필드만 셋업) final List created = []; for (var i = 0; i < eventsData.length; i++) { final e = eventsData[i]; created.add(Event( id: 'e$i', clubId: (e['clubId']?.toString() ?? 'club-1'), title: (e['title']?.toString() ?? 'Untitled'), startDate: DateTime.tryParse(e['startDate']?.toString() ?? '') ?? DateTime(2025, 1, 1), endDate: null, location: e['location']?.toString(), type: e['type']?.toString(), status: e['status']?.toString(), maxParticipants: null, currentParticipants: null, gameCount: null, participantFee: null, registrationDeadline: null, publicHash: null, accessPassword: null, isActive: true, )); } return created; } } void main() { group('EventsScreen 파일 업로드 플로우', () { testWidgets('CSV 바이트 주입으로 성공 플로우 및 결과 다이얼로그 표시/닫기', (tester) async { final auth = StubAuthService(); final club = ClubService.forTest(ApiService()); // 호출되지 않지만 타입 만족 final event = StubEventService(); await tester.pumpWidget( MultiProvider( providers: [ ChangeNotifierProvider.value(value: auth), ChangeNotifierProvider.value(value: club), ChangeNotifierProvider.value(value: event), ], child: const MaterialApp(home: EventsScreen()), ), ); await tester.pump(); // CSV 본문 구성: 2 유효, 1 무효(title 누락) const csv = 'title,startDate,endDate,description,location,status,type,maxParticipants\n' 'Match A,2025-10-01,,,,,,\n' ',2025-10-02,,,,,,\n' 'Match B,2025-10-03,,,,,,\n'; final bytes = Uint8List.fromList(csv.codeUnits); // 테스트 전용 훅으로 임포트 실행 final stateFinder = find.byType(EventsScreen); expect(stateFinder, findsOneWidget); final state = tester.state(stateFinder); await (state as dynamic).importFromBytesForTest('sample.csv', bytes); // 결과 다이얼로그 표시 확인 await tester.pumpAndSettle(const Duration(milliseconds: 300)); expect(find.text('파일 처리 결과'), findsOneWidget); expect(find.textContaining('생성된 이벤트:'), findsOneWidget); expect(find.textContaining('유효하지 않은 행:'), findsOneWidget); // 닫기 눌러 닫힘 확인 final closeBtn = find.text('닫기'); expect(closeBtn, findsOneWidget); await tester.tap(closeBtn); await tester.pumpAndSettle(); // 다이얼로그 사라짐 expect(find.text('파일 처리 결과'), findsNothing); }); }); }