import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:tane/services/notification_service.dart'; class _MockPlugin extends Mock implements FlutterLocalNotificationsPlugin {} void main() { late _MockPlugin plugin; setUpAll(() { registerFallbackValue( const NotificationDetails( android: AndroidNotificationDetails('x', 'x'), ), ); registerFallbackValue(const InitializationSettings()); }); setUp(() { plugin = _MockPlugin(); when(() => plugin.show(any(), any(), any(), any(), payload: any(named: 'payload'))).thenAnswer((_) async {}); // Generic platform resolution returns null, so the permission requests in // initialize() are skipped in tests. when(() => plugin.resolvePlatformSpecificImplementation()) .thenReturn(null); }); test('showMessage passes the title and pubkey payload, no body', () async { final service = NotificationService(plugin: plugin, supported: true); await service.showMessage( peerPubkey: 'abc123', title: 'New message from Alice'); final captured = verify(() => plugin.show( captureAny(), captureAny(), captureAny(), captureAny(), payload: captureAny(named: 'payload'), )).captured; expect(captured[1], 'New message from Alice'); // title expect(captured[2], isNull); // no body (privacy: no message text) expect(captured[4], 'abc123'); // payload = peer pubkey }); test('is a no-op on unsupported platforms (web/windows)', () async { final service = NotificationService(plugin: plugin, supported: false); await service.initialize(); await service.showMessage(peerPubkey: 'abc123', title: 'hi'); verifyNever(() => plugin.show(any(), any(), any(), any(), payload: any(named: 'payload'))); }); test('a tap with a payload invokes onTapChat with the pubkey', () async { // Capture the response handler initialize() registers, then simulate a tap. void Function(NotificationResponse)? handler; when(() => plugin.initialize( any(), onDidReceiveNotificationResponse: any(named: 'onDidReceiveNotificationResponse'), )).thenAnswer((inv) async { handler = inv.namedArguments[#onDidReceiveNotificationResponse] as void Function(NotificationResponse)?; return true; }); final service = NotificationService(plugin: plugin, supported: true); String? tapped; service.onTapChat = (pk) => tapped = pk; await service.initialize(); handler!(const NotificationResponse( notificationResponseType: NotificationResponseType.selectedNotification, payload: 'abc123', )); expect(tapped, 'abc123'); }); }