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/services/event_service.dart'; import 'package:lanebow/screens/club/participant_form_screen.dart'; import '../../utils/event_bus_test_utils.dart'; import 'package:lanebow/utils/test_utils.dart'; // 공통 StubEventService 사용 import '../../utils/stub_event_service.dart'; import '../../utils/dummy_test_data.dart'; void main() { late EventService stubEventService; setUp(() async { // EventBus 테스트 환경 초기화 (플래키 방지) TestUtils.setTestMode(true); await EventBusTestUtils.setUp('participant_form_screen_test'); stubEventService = StubEventService(); }); tearDown(() async { await EventBusTestUtils.tearDown(); }); // 로컬 더미 생성기 제거: DummyTestData 공용 유틸 사용 // 위젯 빌더 Widget createParticipantForm({ required String eventId, Participant? participant, }) { return MaterialApp( home: ChangeNotifierProvider.value( value: stubEventService, child: ParticipantFormScreen( eventId: eventId, participant: participant, ), ), ); } group('ParticipantFormScreen 위젯 테스트', () { testWidgets('새 참가자 추가 모드: 필수값 입력 후 저장 플로우', (tester) async { await tester.pumpWidget(createParticipantForm(eventId: 'event1')); await tester.pumpAndSettle(); // 이름 입력 (필수) final nameField = find.widgetWithText(TextFormField, '이름 *'); expect(nameField, findsOneWidget); await tester.enterText(nameField, '홍길동'); // 저장 아이콘 버튼 탭 await tester.tap(find.byIcon(Icons.save)); await tester.pump(const Duration(milliseconds: 300)); await tester.pump(const Duration(seconds: 1)); // then: 화면이 pop 되었는지 확인 (성공 시 Navigator.pop(true) 호출) expect(find.byType(ParticipantFormScreen), findsNothing); }); testWidgets('참가자 수정 모드: 수정 후 저장 플로우', (tester) async { // given final existing = DummyTestData.participants(eventId: 'event1', count: 1, status: '확인됨').first; await tester.pumpWidget(createParticipantForm(eventId: 'event1', participant: existing)); await tester.pumpAndSettle(); // 제목이 수정 모드로 표시되는지 확인 expect(find.text('참가자 수정'), findsWidgets); // 이름 변경 final nameField = find.widgetWithText(TextFormField, '이름 *'); expect(nameField, findsOneWidget); await tester.enterText(nameField, '수정된이름'); // 저장 await tester.tap(find.byIcon(Icons.save)); await tester.pump(const Duration(milliseconds: 300)); await tester.pump(const Duration(seconds: 1)); // then: 화면이 pop 되었는지 확인 expect(find.byType(ParticipantFormScreen), findsNothing); }); testWidgets('실패 케이스(추가): 스낵바 에러 노출, 로딩 해제, pop 미호출', (tester) async { // given (stubEventService as StubEventService).throwOnAddParticipant = true; await tester.pumpWidget(createParticipantForm(eventId: 'event1')); await tester.pumpAndSettle(); // 이름 입력 final nameField = find.widgetWithText(TextFormField, '이름 *'); expect(nameField, findsOneWidget); await tester.enterText(nameField, '실패사례'); // when: 저장 클릭 await tester.tap(find.byIcon(Icons.save)); await tester.pump(const Duration(milliseconds: 300)); await tester.pump(const Duration(seconds: 1)); // then: 화면이 여전히 존재 (pop 미호출) expect(find.byType(ParticipantFormScreen), findsOneWidget); // 에러 스낵바 노출 expect(find.textContaining('참가자 저장에 실패했습니다'), findsOneWidget); }); testWidgets('실패 케이스(수정): 스낵바 에러 노출, 로딩 해제, pop 미호출', (tester) async { // given (stubEventService as StubEventService).throwOnUpdateParticipant = true; final existing = DummyTestData.participants(eventId: 'event1', count: 1, status: '확인됨').first; await tester.pumpWidget(createParticipantForm(eventId: 'event1', participant: existing)); await tester.pumpAndSettle(); // 이름 변경 final nameField = find.widgetWithText(TextFormField, '이름 *'); expect(nameField, findsOneWidget); await tester.enterText(nameField, '변경실패'); // when: 저장 클릭 await tester.tap(find.byIcon(Icons.save)); await tester.pump(const Duration(milliseconds: 300)); await tester.pump(const Duration(seconds: 1)); // then expect(find.byType(ParticipantFormScreen), findsOneWidget); expect(find.textContaining('참가자 저장에 실패했습니다'), findsOneWidget); }); }); }