147 lines
4.5 KiB
Dart
147 lines
4.5 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:mocktail/mocktail.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:social_app/core/notifications/local_notification_service.dart';
|
|
import 'package:social_app/core/notifications/reminder_notification_callbacks.dart';
|
|
import 'package:social_app/features/calendar/reminders/models/reminder_action.dart';
|
|
import 'package:social_app/features/calendar/reminders/models/reminder_payload.dart';
|
|
|
|
class MockFlutterLocalNotificationsPlugin extends Mock
|
|
implements FlutterLocalNotificationsPlugin {}
|
|
|
|
void main() {
|
|
setUpAll(() {
|
|
registerFallbackValue(
|
|
const InitializationSettings(
|
|
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
|
|
iOS: DarwinInitializationSettings(),
|
|
),
|
|
);
|
|
});
|
|
|
|
late MockFlutterLocalNotificationsPlugin plugin;
|
|
late LocalNotificationService service;
|
|
late List<ReminderAction> handledActions;
|
|
late List<ReminderPayload> presentedPayloads;
|
|
DidReceiveNotificationResponseCallback? callback;
|
|
|
|
setUp(() async {
|
|
SharedPreferences.setMockInitialValues({});
|
|
plugin = MockFlutterLocalNotificationsPlugin();
|
|
service = LocalNotificationService(plugin: plugin);
|
|
handledActions = <ReminderAction>[];
|
|
presentedPayloads = <ReminderPayload>[];
|
|
|
|
when(
|
|
() => plugin.initialize(
|
|
any(),
|
|
onDidReceiveNotificationResponse: any(
|
|
named: 'onDidReceiveNotificationResponse',
|
|
),
|
|
onDidReceiveBackgroundNotificationResponse: any(
|
|
named: 'onDidReceiveBackgroundNotificationResponse',
|
|
),
|
|
),
|
|
).thenAnswer((invocation) async {
|
|
callback =
|
|
invocation.namedArguments[#onDidReceiveNotificationResponse]
|
|
as DidReceiveNotificationResponseCallback?;
|
|
return true;
|
|
});
|
|
|
|
when(
|
|
() => plugin
|
|
.resolvePlatformSpecificImplementation<
|
|
AndroidFlutterLocalNotificationsPlugin
|
|
>(),
|
|
).thenReturn(null);
|
|
when(
|
|
() => plugin
|
|
.resolvePlatformSpecificImplementation<
|
|
IOSFlutterLocalNotificationsPlugin
|
|
>(),
|
|
).thenReturn(null);
|
|
|
|
service.bindActionHandler(({required action, required payload}) async {
|
|
handledActions.add(action);
|
|
});
|
|
service.bindInAppReminderHandler((payload) async {
|
|
presentedPayloads.add(payload);
|
|
});
|
|
await ReminderNotificationCallbacks.bindResponseHandler(
|
|
service.handleNotificationResponse,
|
|
);
|
|
|
|
await service.initialize();
|
|
});
|
|
|
|
test('cancel action from system notification maps to archive', () async {
|
|
callback!(
|
|
NotificationResponse(
|
|
notificationResponseType:
|
|
NotificationResponseType.selectedNotificationAction,
|
|
id: 101,
|
|
actionId: 'cancel',
|
|
payload: jsonEncode(
|
|
ReminderPayload(
|
|
eventId: 'evt_1',
|
|
title: 'sync',
|
|
startAt: DateTime.parse('2026-03-19T10:00:00+08:00'),
|
|
timezone: 'Asia/Shanghai',
|
|
).toJson(),
|
|
),
|
|
),
|
|
);
|
|
await Future<void>.delayed(Duration.zero);
|
|
|
|
expect(handledActions, [ReminderAction.archive]);
|
|
});
|
|
|
|
test('duplicate notification response is handled only once', () async {
|
|
final response = NotificationResponse(
|
|
notificationResponseType:
|
|
NotificationResponseType.selectedNotificationAction,
|
|
id: 201,
|
|
actionId: 'cancel',
|
|
payload: jsonEncode(
|
|
ReminderPayload(
|
|
eventId: 'evt_2',
|
|
title: 'retro',
|
|
startAt: DateTime.parse('2026-03-19T11:00:00+08:00'),
|
|
timezone: 'Asia/Shanghai',
|
|
).toJson(),
|
|
),
|
|
);
|
|
|
|
callback!(response);
|
|
callback!(response);
|
|
await Future<void>.delayed(Duration.zero);
|
|
|
|
expect(handledActions, [ReminderAction.archive]);
|
|
});
|
|
|
|
test('notification body tap forwards payload to in-app presenter', () async {
|
|
callback!(
|
|
NotificationResponse(
|
|
notificationResponseType: NotificationResponseType.selectedNotification,
|
|
id: 301,
|
|
payload: jsonEncode(
|
|
ReminderPayload(
|
|
eventId: 'evt_3',
|
|
title: 'daily sync',
|
|
startAt: DateTime.parse('2026-03-19T12:00:00+08:00'),
|
|
timezone: 'Asia/Shanghai',
|
|
).toJson(),
|
|
),
|
|
),
|
|
);
|
|
await Future<void>.delayed(Duration.zero);
|
|
|
|
expect(presentedPayloads.map((item) => item.eventId), ['evt_3']);
|
|
expect(handledActions, isEmpty);
|
|
});
|
|
}
|