mattermost-push-plugin/test/mattermost_push_plugin_test.dart

179 lines
5.4 KiB
Dart

import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mattermost_push_plugin/mattermost_push_plugin.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('NotificationOpenedEvent.fromMap', () {
test('parses server_url, channel_id, root_id, is_crt_enabled', () {
final event = NotificationOpenedEvent.fromMap({
'server_url': 'https://mm.example.com',
'channel_id': 'channel-123',
'root_id': 'root-456',
'is_crt_enabled': 'true',
});
expect(event.serverUrl, 'https://mm.example.com');
expect(event.channelId, 'channel-123');
expect(event.rootId, 'root-456');
expect(event.isCRTEnabled, isTrue);
});
test('defaults isCRTEnabled to false when flag is absent or non-true', () {
final missing = NotificationOpenedEvent.fromMap({
'server_url': 'https://mm.example.com',
'channel_id': 'channel-123',
});
expect(missing.isCRTEnabled, isFalse);
final falsy = NotificationOpenedEvent.fromMap({
'is_crt_enabled': 'false',
});
expect(falsy.isCRTEnabled, isFalse);
});
});
group('MattermostPushPlugin.handleNativeEvent', () {
late MattermostPushPlugin plugin;
final actionChannel = MethodChannel(MattermostPushPlugin.actionChannelName);
setUp(() {
plugin = MattermostPushPlugin.instance;
plugin.onNavigateToChannel = null;
plugin.onNavigateToThread = null;
plugin.onDeviceTokenReady = null;
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(actionChannel, null);
});
test('opened event emits NotificationOpenedEvent on stream', () async {
final future = plugin.onNotificationOpened.first;
plugin.handleNativeEvent({
'type': PushNotificationType.opened,
'server_url': 'https://mm.example.com',
'channel_id': 'channel-123',
});
final event = await future;
expect(event.serverUrl, 'https://mm.example.com');
expect(event.channelId, 'channel-123');
});
test(
'message event with userInteraction routes through opened handler',
() async {
String? navServer;
String? navChannel;
plugin.onNavigateToChannel = (s, c) {
navServer = s;
navChannel = c;
};
plugin.handleNativeEvent({
'type': PushNotificationType.message,
'userInteraction': true,
'server_url': 'https://mm.example.com',
'channel_id': 'channel-xyz',
});
expect(navServer, 'https://mm.example.com');
expect(navChannel, 'channel-xyz');
},
);
test('opened event with CRT and rootId routes to thread callback', () {
String? navServer;
String? navRoot;
plugin.onNavigateToThread = (s, r) {
navServer = s;
navRoot = r;
};
plugin.handleNativeEvent({
'type': PushNotificationType.opened,
'server_url': 'https://mm.example.com',
'channel_id': 'channel-123',
'root_id': 'root-789',
'is_crt_enabled': 'true',
});
expect(navServer, 'https://mm.example.com');
expect(navRoot, 'root-789');
});
test('opened event without server_url skips navigation callbacks', () {
var channelCalled = false;
var threadCalled = false;
plugin.onNavigateToChannel = (_, _) => channelCalled = true;
plugin.onNavigateToThread = (_, _) => threadCalled = true;
plugin.handleNativeEvent({
'type': PushNotificationType.opened,
'channel_id': 'channel-123',
});
expect(channelCalled, isFalse);
expect(threadCalled, isFalse);
});
test('every event is forwarded to onNotification stream', () async {
final future = plugin.onNotification.first;
plugin.handleNativeEvent({
'type': PushNotificationType.clear,
'channel_id': 'channel-123',
});
final raw = await future;
expect(raw['type'], PushNotificationType.clear);
expect(raw['channel_id'], 'channel-123');
});
test(
'token_refresh event saves formatted device token and invokes callback',
() async {
String? channelToken;
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(actionChannel, (call) async {
if (call.method == 'saveDeviceToken') {
final args = call.arguments as Map;
channelToken = args['token'] as String?;
}
return null;
});
final completer = Completer<String>();
plugin.onDeviceTokenReady = completer.complete;
plugin.handleNativeEvent({
'type': PushNotificationType.tokenRefresh,
'token': 'raw-token',
});
final callbackToken = await completer.future;
expect(channelToken, 'android_rn-v2:raw-token');
expect(callbackToken, 'android_rn-v2:raw-token');
},
);
});
group('Channel constants', () {
test('notification and action channel names are preserved', () {
expect(
MattermostPushPlugin.notificationChannelName,
'com.tokilabs.mattermost/notifications',
);
expect(
MattermostPushPlugin.actionChannelName,
'com.tokilabs.mattermost/notification_actions',
);
});
});
}