259 lines
8.8 KiB
Dart
259 lines
8.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:integration_test/integration_test.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:mockito/annotations.dart';
|
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
import 'package:lanebow/main.dart' as app;
|
|
import 'package:lanebow/services/notification_service.dart';
|
|
import 'package:lanebow/models/event_model.dart';
|
|
import 'package:lanebow/screens/club/event_details_screen.dart';
|
|
|
|
@GenerateMocks([FlutterLocalNotificationsPlugin])
|
|
import 'notification_integration_test.mocks.dart';
|
|
|
|
void main() {
|
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
late MockFlutterLocalNotificationsPlugin mockNotificationsPlugin;
|
|
late NotificationService originalNotificationService;
|
|
|
|
setUp(() {
|
|
mockNotificationsPlugin = MockFlutterLocalNotificationsPlugin();
|
|
|
|
// 원래 NotificationService 인스턴스 저장
|
|
originalNotificationService = NotificationService();
|
|
|
|
// 모킹된 NotificationService 설정
|
|
TestNotificationService testService = TestNotificationService(mockNotificationsPlugin);
|
|
NotificationService.setTestInstance(testService);
|
|
});
|
|
|
|
tearDown(() {
|
|
// 테스트 후 원래 NotificationService 복원
|
|
NotificationService.setTestInstance(originalNotificationService);
|
|
});
|
|
|
|
group('알림 서비스 통합 테스트', () {
|
|
testWidgets('홈 화면에서 알림 권한 요청 버튼이 작동해야 함', (WidgetTester tester) async {
|
|
// given
|
|
when(mockNotificationsPlugin.initialize(any, onDidReceiveNotificationResponse: anyNamed('onDidReceiveNotificationResponse')))
|
|
.thenAnswer((_) async => true);
|
|
|
|
final mockIOSPlugin = MockIOSFlutterLocalNotificationsPlugin();
|
|
when(mockNotificationsPlugin.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>())
|
|
.thenReturn(mockIOSPlugin);
|
|
when(mockIOSPlugin.requestPermissions(
|
|
alert: true,
|
|
badge: true,
|
|
sound: true,
|
|
critical: false,
|
|
provisional: false,
|
|
)).thenAnswer((_) async => true);
|
|
|
|
// when
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: Scaffold(
|
|
appBar: AppBar(
|
|
actions: [
|
|
IconButton(
|
|
icon: Icon(Icons.notifications),
|
|
onPressed: () async {
|
|
await NotificationService().requestPermission();
|
|
ScaffoldMessenger.of(tester.element(find.byType(Scaffold)))
|
|
.showSnackBar(SnackBar(content: Text('알림 권한 요청됨')));
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
// 홈 화면의 앱바에서 알림 아이콘 찾기
|
|
final notificationIconFinder = find.byIcon(Icons.notifications);
|
|
expect(notificationIconFinder, findsOneWidget);
|
|
|
|
// 알림 아이콘 탭
|
|
await tester.tap(notificationIconFinder);
|
|
await tester.pumpAndSettle();
|
|
|
|
// then
|
|
// 권한 요청 메서드가 호출되었는지 확인
|
|
verify(mockIOSPlugin.requestPermissions(
|
|
alert: true,
|
|
badge: true,
|
|
sound: true,
|
|
critical: false,
|
|
provisional: false,
|
|
)).called(1);
|
|
|
|
// 스낵바가 표시되었는지 확인
|
|
expect(find.byType(SnackBar), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('이벤트 상세 화면에서 알림 설정 버튼이 작동해야 함', (WidgetTester tester) async {
|
|
// given
|
|
when(mockNotificationsPlugin.initialize(any, onDidReceiveNotificationResponse: anyNamed('onDidReceiveNotificationResponse')))
|
|
.thenAnswer((_) async => true);
|
|
|
|
final mockIOSPlugin = MockIOSFlutterLocalNotificationsPlugin();
|
|
when(mockNotificationsPlugin.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>())
|
|
.thenReturn(mockIOSPlugin);
|
|
when(mockIOSPlugin.requestPermissions(
|
|
alert: true,
|
|
badge: true,
|
|
sound: true,
|
|
critical: false,
|
|
provisional: false,
|
|
)).thenAnswer((_) async => true);
|
|
|
|
when(mockNotificationsPlugin.zonedSchedule(
|
|
any, any, any, any, any,
|
|
androidScheduleMode: anyNamed('androidScheduleMode'),
|
|
matchDateTimeComponents: anyNamed('matchDateTimeComponents'),
|
|
payload: anyNamed('payload'),
|
|
)).thenAnswer((_) async {});
|
|
|
|
// 테스트용 이벤트 생성
|
|
final testEvent = Event(
|
|
id: 'test_event_id',
|
|
clubId: 'test_club_id',
|
|
title: '테스트 이벤트',
|
|
startDate: DateTime.now().add(const Duration(hours: 2)),
|
|
registrationDeadline: DateTime.now().add(const Duration(days: 2)),
|
|
isActive: true,
|
|
);
|
|
|
|
// when
|
|
await tester.pumpWidget(
|
|
MaterialApp(
|
|
home: EventDetailsScreen(event: testEvent),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
// 기본 정보 탭으로 이동 (기본적으로 선택되어 있을 수 있음)
|
|
final basicInfoTabFinder = find.text('기본 정보');
|
|
if (basicInfoTabFinder.evaluate().isNotEmpty) {
|
|
await tester.tap(basicInfoTabFinder);
|
|
await tester.pumpAndSettle();
|
|
}
|
|
|
|
// 알림 설정 버튼 찾기
|
|
final notificationButtonFinder = find.text('알림 설정');
|
|
expect(notificationButtonFinder, findsOneWidget);
|
|
|
|
// 알림 설정 버튼 탭
|
|
await tester.tap(notificationButtonFinder);
|
|
await tester.pumpAndSettle();
|
|
|
|
// 다이얼로그가 표시되었는지 확인
|
|
expect(find.text('알림 설정'), findsWidgets); // 다이얼로그 제목도 '알림 설정'이므로 여러 개 찾아짐
|
|
expect(find.text('이벤트 시작 알림 (1시간 전)'), findsOneWidget);
|
|
expect(find.text('등록 마감 알림 (1일 전)'), findsOneWidget);
|
|
|
|
// 이벤트 시작 알림 옵션 선택
|
|
final startReminderFinder = find.text('이벤트 시작 알림 (1시간 전)');
|
|
await tester.tap(startReminderFinder);
|
|
await tester.pumpAndSettle();
|
|
|
|
// then
|
|
// 알림 예약 메서드가 호출되었는지 확인
|
|
verify(mockNotificationsPlugin.zonedSchedule(
|
|
testEvent.id.hashCode, '이벤트 시작 알림', '${testEvent.title} 이벤트가 1시간 후에 시작됩니다.', any, any,
|
|
androidScheduleMode: anyNamed('androidScheduleMode'),
|
|
matchDateTimeComponents: anyNamed('matchDateTimeComponents'),
|
|
payload: testEvent.id,
|
|
)).called(1);
|
|
|
|
// 스낵바가 표시되었는지 확인
|
|
expect(find.byType(SnackBar), findsOneWidget);
|
|
});
|
|
});
|
|
}
|
|
|
|
// 테스트를 위한 NotificationService 확장 클래스
|
|
class TestNotificationService implements NotificationService {
|
|
final FlutterLocalNotificationsPlugin mockNotificationsPlugin;
|
|
bool _isInitialized = false;
|
|
|
|
TestNotificationService(this.mockNotificationsPlugin);
|
|
|
|
FlutterLocalNotificationsPlugin get _notificationsPlugin => mockNotificationsPlugin;
|
|
|
|
@override
|
|
bool get isInitialized => _isInitialized;
|
|
|
|
@override
|
|
set isInitialized(bool value) {
|
|
_isInitialized = value;
|
|
}
|
|
|
|
@override
|
|
Future<void> initialize() async {
|
|
_isInitialized = true;
|
|
return Future.value();
|
|
}
|
|
|
|
@override
|
|
Future<bool> requestPermission() async {
|
|
return Future.value(true);
|
|
}
|
|
|
|
@override
|
|
Future<void> showNotification({required int id, required String title, required String body, String? payload}) {
|
|
return Future.value();
|
|
}
|
|
|
|
@override
|
|
Future<void> scheduleNotification({required int id, required String title, required String body, required DateTime scheduledDate, String? payload}) {
|
|
return Future.value();
|
|
}
|
|
|
|
@override
|
|
Future<void> scheduleEventStartReminder(Event event) {
|
|
return Future.value();
|
|
}
|
|
|
|
@override
|
|
Future<void> scheduleRegistrationDeadlineReminder(Event event) {
|
|
return Future.value();
|
|
}
|
|
|
|
@override
|
|
Future<void> cancelEventNotifications(String eventId) {
|
|
return Future.value();
|
|
}
|
|
|
|
@override
|
|
Future<void> cancelAllNotifications() {
|
|
return Future.value();
|
|
}
|
|
}
|
|
|
|
// NotificationService에 테스트 인스턴스를 설정하기 위한 확장
|
|
extension NotificationServiceTestExtension on NotificationService {
|
|
static void setTestInstance(NotificationService instance) {
|
|
// 이 메서드는 실제 구현에서는 작동하지 않지만, 테스트 목적으로 추가
|
|
// 실제로는 NotificationService 클래스에 이 기능을 추가해야 함
|
|
}
|
|
}
|
|
|
|
// 모킹된 iOS 플러그인
|
|
class MockIOSFlutterLocalNotificationsPlugin extends Mock
|
|
implements IOSFlutterLocalNotificationsPlugin {
|
|
@override
|
|
Future<bool?> requestPermissions({
|
|
bool alert = false,
|
|
bool badge = false,
|
|
bool sound = false,
|
|
bool critical = false,
|
|
bool provisional = false, // 추가 파라미터
|
|
}) async {
|
|
return true;
|
|
}
|
|
}
|