152 lines
4.6 KiB
Dart
152 lines
4.6 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:scheduler_notifications/notifications.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import '../../scheduler_notifications/test/notification_adapter_contract.dart';
|
|
|
|
// ignore: avoid_relative_lib_imports
|
|
import '../lib/desktop_notifications.dart';
|
|
|
|
void main() {
|
|
runNotificationAdapterContractTests('desktop', () {
|
|
final backend = _RecordingBackend();
|
|
return NotificationAdapterContractHarness(
|
|
adapter: DesktopNotificationAdapter(backend: backend),
|
|
scheduledRequests: () => backend.delivered,
|
|
cancelledIds: () => backend.cancelled,
|
|
);
|
|
});
|
|
|
|
test('desktop adapter delegates schedule and cancel to backend', () async {
|
|
final backend = _RecordingBackend();
|
|
final adapter = DesktopNotificationAdapter(backend: backend);
|
|
final request = _request('reminder-1');
|
|
|
|
await adapter.schedule(request);
|
|
await adapter.cancel(' reminder-1 ');
|
|
|
|
expect(backend.delivered, [request]);
|
|
expect(backend.cancelled, ['reminder-1']);
|
|
expect(adapter, isA<NotificationAdapter>());
|
|
});
|
|
|
|
test('linux backend invokes notify-send', () async {
|
|
final calls = <_ProcessCall>[];
|
|
final logs = <String>[];
|
|
final backend = createDefaultDesktopNotificationBackend(
|
|
platform: DesktopNotificationPlatform.linux,
|
|
processRunner: (executable, arguments) async {
|
|
calls.add(_ProcessCall(executable, arguments));
|
|
return ProcessResult(1, 0, '', '');
|
|
},
|
|
logSink: logs.add,
|
|
);
|
|
|
|
await backend.deliver(_request('reminder-1'));
|
|
|
|
expect(backend.isSupported, isTrue);
|
|
expect(calls.single.executable, 'notify-send');
|
|
expect(calls.single.arguments, contains('Start task'));
|
|
expect(logs, isEmpty);
|
|
});
|
|
|
|
test('macOS backend invokes osascript', () async {
|
|
final calls = <_ProcessCall>[];
|
|
final backend = createDefaultDesktopNotificationBackend(
|
|
platform: DesktopNotificationPlatform.macos,
|
|
processRunner: (executable, arguments) async {
|
|
calls.add(_ProcessCall(executable, arguments));
|
|
return ProcessResult(1, 0, '', '');
|
|
},
|
|
);
|
|
|
|
await backend.deliver(_request('reminder-1'));
|
|
|
|
expect(backend.isSupported, isTrue);
|
|
expect(calls.single.executable, 'osascript');
|
|
expect(calls.single.arguments, contains('-e'));
|
|
});
|
|
|
|
test('unsupported and Windows platforms fall back to log output', () async {
|
|
final logs = <String>[];
|
|
final windows = createDefaultDesktopNotificationBackend(
|
|
platform: DesktopNotificationPlatform.windows,
|
|
logSink: logs.add,
|
|
);
|
|
final unsupported = createDefaultDesktopNotificationBackend(
|
|
platform: DesktopNotificationPlatform.unsupported,
|
|
logSink: logs.add,
|
|
);
|
|
|
|
await windows.deliver(_request('windows-reminder'));
|
|
await unsupported.cancel(' unsupported-reminder ');
|
|
|
|
expect(windows.isSupported, isFalse);
|
|
expect(unsupported.isSupported, isFalse);
|
|
expect(logs.first, contains('windows-reminder'));
|
|
expect(logs.last, contains('unsupported-reminder'));
|
|
});
|
|
|
|
test('fake adapter can stand in for scheduling workflows', () async {
|
|
final adapter = FakeNotificationAdapter();
|
|
addTearDown(adapter.close);
|
|
await _scheduleAndCancelReminder(adapter, _request('reminder-1'));
|
|
|
|
expect(adapter.scheduledRequests, isEmpty);
|
|
expect(adapter.cancelledIds, ['reminder-1']);
|
|
});
|
|
|
|
test('default desktop adapter can be created on supported test platforms',
|
|
() {
|
|
if (!Platform.isLinux && !Platform.isMacOS && !Platform.isWindows) {
|
|
markTestSkipped(
|
|
'Desktop notifications are unsupported on this platform.');
|
|
}
|
|
|
|
expect(DesktopNotificationAdapter.defaultInstance(),
|
|
isA<NotificationAdapter>());
|
|
});
|
|
}
|
|
|
|
Future<void> _scheduleAndCancelReminder(
|
|
NotificationAdapter adapter,
|
|
NotificationRequest request,
|
|
) async {
|
|
await adapter.schedule(request);
|
|
await adapter.cancel(request.id);
|
|
}
|
|
|
|
NotificationRequest _request(String id) {
|
|
return NotificationRequest(
|
|
id: id,
|
|
title: 'Start task',
|
|
body: 'Time to begin.',
|
|
scheduledDateTimeUtc: DateTime.utc(2026, 1, 1, 9),
|
|
);
|
|
}
|
|
|
|
final class _RecordingBackend implements DesktopNotificationBackend {
|
|
final List<NotificationRequest> delivered = <NotificationRequest>[];
|
|
final List<String> cancelled = <String>[];
|
|
|
|
@override
|
|
bool get isSupported => true;
|
|
|
|
@override
|
|
Future<void> deliver(NotificationRequest request) async {
|
|
delivered.add(request);
|
|
}
|
|
|
|
@override
|
|
Future<void> cancel(String id) async {
|
|
cancelled.add(id);
|
|
}
|
|
}
|
|
|
|
final class _ProcessCall {
|
|
const _ProcessCall(this.executable, this.arguments);
|
|
|
|
final String executable;
|
|
final List<String> arguments;
|
|
}
|