import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:provider/provider.dart'; import 'package:lanebow/models/participant_model.dart'; import 'package:lanebow/screens/club/participant_form_screen.dart'; import 'package:lanebow/services/event_service.dart'; class FakeEventService extends EventService { Map? lastPayload; String? lastEventId; String? lastParticipantId; bool addCalled = false; bool updateCalled = false; // EventService의 공개 API 중 테스트에 필요한 최소 메서드만 구현 @override Future addParticipant(String eventId, Map participantData) async { lastEventId = eventId; lastPayload = participantData; addCalled = true; // 응답은 신규 Participant로 모의 return Participant( id: 'new-1', eventId: eventId, memberId: '', name: participantData['name'] as String?, email: participantData['email'] as String?, phoneNumber: participantData['phoneNumber'] as String?, status: participantData['status'] as String?, isPaid: participantData['isPaid'] as bool? ?? false, paidAmount: participantData['paidAmount'] as double?, notes: participantData['notes'] as String?, ); } @override Future updateParticipant(String eventId, String participantId, Map participantData) async { lastEventId = eventId; lastParticipantId = participantId; lastPayload = participantData; updateCalled = true; return Participant( id: participantId, eventId: eventId, memberId: '', name: participantData['name'] as String?, email: participantData['email'] as String?, phoneNumber: participantData['phoneNumber'] as String?, status: participantData['status'] as String?, isPaid: participantData['isPaid'] as bool? ?? false, paidAmount: participantData['paidAmount'] as double?, notes: participantData['notes'] as String?, ); } // 나머지는 사용하지 않음 } Widget _wrapWithProviders(Widget child, EventService service) { return MultiProvider( providers: [ ChangeNotifierProvider.value(value: service), ], child: MaterialApp(home: child), ); } void main() { group('ParticipantFormScreen', () { testWidgets('편집 모드: 영문 status와 isPaid가 저장 시 올바르게 전송되고 paymentStatus 포함', (tester) async { final fakeService = FakeEventService(); final participant = Participant( id: 'p1', eventId: 'e1', memberId: 'm1', name: '홍길동', status: 'confirmed', isPaid: true, ); await tester.pumpWidget( _wrapWithProviders( ParticipantFormScreen(eventId: 'e1', participant: participant), fakeService, ), ); // 저장 아이콘 탭 final saveButton = find.byIcon(Icons.save); expect(saveButton, findsOneWidget); await tester.tap(saveButton); await tester.pumpAndSettle(); expect(fakeService.updateCalled, isTrue); expect(fakeService.lastEventId, 'e1'); expect(fakeService.lastParticipantId, 'p1'); // 상태는 영문으로 전송되어야 함 expect(fakeService.lastPayload!['status'], 'confirmed'); // 결제 상태 동기화 expect(fakeService.lastPayload!['isPaid'], isTrue); expect(fakeService.lastPayload!['paymentStatus'], 'paid'); }); testWidgets('편집 모드: 알 수 없는 status는 안전 기본값(pending)으로 전송', (tester) async { final fakeService = FakeEventService(); final participant = Participant( id: 'p2', eventId: 'e2', memberId: 'm2', name: '아무개', status: 'unknown', isPaid: false, ); await tester.pumpWidget( _wrapWithProviders( ParticipantFormScreen(eventId: 'e2', participant: participant), fakeService, ), ); // 저장 await tester.tap(find.byIcon(Icons.save)); await tester.pumpAndSettle(); expect(fakeService.updateCalled, isTrue); expect(fakeService.lastPayload!['status'], 'pending'); expect(fakeService.lastPayload!['paymentStatus'], 'unpaid'); }); testWidgets('추가 모드: 빈 이메일/전화/메모는 명시적 null로 전송', (tester) async { final fakeService = FakeEventService(); await tester.pumpWidget( _wrapWithProviders( const ParticipantFormScreen(eventId: 'evt-1'), fakeService, ), ); // 필수 이름 입력 await tester.enterText(find.byType(TextFormField).first, '새 참가자'); // 저장 await tester.tap(find.byIcon(Icons.save)); await tester.pumpAndSettle(); expect(fakeService.addCalled, isTrue); expect(fakeService.lastPayload!['email'], isNull); expect(fakeService.lastPayload!['phoneNumber'], isNull); expect(fakeService.lastPayload!['notes'], isNull); }); }); }