Skip to content

Commit b743ba1

Browse files
authored
test: improve test coverage (#1077)
1 parent ec664ac commit b743ba1

File tree

8 files changed

+1724
-9
lines changed

8 files changed

+1724
-9
lines changed

lib/src/notifications.dart

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:async';
2-
import 'dart:io';
2+
3+
import 'package:flutter/foundation.dart';
34
import 'package:flutter/services.dart';
45
import 'package:onesignal_flutter/src/defines.dart';
56
import 'package:onesignal_flutter/src/notification.dart';
@@ -25,7 +26,7 @@ class OneSignalNotifications {
2526
<OnNotificationPermissionChangeObserver>[];
2627
// constructor method
2728
OneSignalNotifications() {
28-
this._channel.setMethodCallHandler(_handleMethod);
29+
this._channel.setMethodCallHandler(handleMethod);
2930
}
3031

3132
bool _permission = false;
@@ -45,7 +46,7 @@ class OneSignalNotifications {
4546
/// provisional, // only available in iOS 12
4647
/// ephemeral, // only available in iOS 14
4748
Future<OSNotificationPermission> permissionNative() async {
48-
if (Platform.isIOS) {
49+
if (defaultTargetPlatform == TargetPlatform.iOS) {
4950
return OSNotificationPermission
5051
.values[await _channel.invokeMethod("OneSignal#permissionNative")];
5152
} else {
@@ -63,15 +64,15 @@ class OneSignalNotifications {
6364

6465
/// Removes a single notification.
6566
Future<void> removeNotification(int notificationId) async {
66-
if (Platform.isAndroid) {
67+
if (defaultTargetPlatform == TargetPlatform.android) {
6768
return await _channel.invokeMethod(
6869
"OneSignal#removeNotification", {'notificationId': notificationId});
6970
}
7071
}
7172

7273
/// Removes a grouped notification.
7374
Future<void> removeGroupedNotifications(String notificationGroup) async {
74-
if (Platform.isAndroid) {
75+
if (defaultTargetPlatform == TargetPlatform.android) {
7576
return await _channel.invokeMethod("OneSignal#removeGroupedNotifications",
7677
{'notificationGroup': notificationGroup});
7778
}
@@ -93,7 +94,7 @@ class OneSignalNotifications {
9394
/// your app can request provisional authorization.
9495
Future<bool> registerForProvisionalAuthorization(
9596
bool fallbackToSettings) async {
96-
if (Platform.isIOS) {
97+
if (defaultTargetPlatform == TargetPlatform.iOS) {
9798
return await _channel
9899
.invokeMethod("OneSignal#registerForProvisionalAuthorization");
99100
} else {
@@ -122,7 +123,7 @@ class OneSignalNotifications {
122123
return await _channel.invokeMethod("OneSignal#lifecycleInit");
123124
}
124125

125-
Future<Null> _handleMethod(MethodCall call) async {
126+
Future<Null> handleMethod(MethodCall call) async {
126127
if (call.method == 'OneSignal#onClickNotification') {
127128
for (var listener in _clickListeners) {
128129
listener(

test/mock_channel.dart

Lines changed: 182 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ class OneSignalMockChannelController {
2020
const MethodChannel('OneSignal#liveactivities');
2121
final MethodChannel _notificationsChannel =
2222
const MethodChannel('OneSignal#notifications');
23+
final MethodChannel _pushSubscriptionChannel =
24+
const MethodChannel('OneSignal#pushsubscription');
25+
final MethodChannel _sessionChannel =
26+
const MethodChannel('OneSignal#session');
27+
final MethodChannel _userChannel = const MethodChannel('OneSignal#user');
2328

2429
late OneSignalState state;
2530

@@ -38,12 +43,42 @@ class OneSignalMockChannelController {
3843
.setMockMethodCallHandler(_liveActivitiesChannel, _handleMethod);
3944
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
4045
.setMockMethodCallHandler(_notificationsChannel, _handleMethod);
46+
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
47+
.setMockMethodCallHandler(_pushSubscriptionChannel, _handleMethod);
48+
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
49+
.setMockMethodCallHandler(_sessionChannel, _handleMethod);
50+
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
51+
.setMockMethodCallHandler(_userChannel, _handleMethod);
4152
}
4253

4354
void resetState() {
4455
state = OneSignalState();
4556
}
4657

58+
// Helper method to simulate push subscription changes from native
59+
void simulatePushSubscriptionChange(Map<String, dynamic> changeData) {
60+
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
61+
.handlePlatformMessage(
62+
_pushSubscriptionChannel.name,
63+
_pushSubscriptionChannel.codec.encodeMethodCall(
64+
MethodCall('OneSignal#onPushSubscriptionChange', changeData),
65+
),
66+
(ByteData? data) {},
67+
);
68+
}
69+
70+
// Helper method to simulate user state changes from native
71+
void simulateUserStateChange(Map<String, dynamic> changeData) {
72+
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
73+
.handlePlatformMessage(
74+
_userChannel.name,
75+
_userChannel.codec.encodeMethodCall(
76+
MethodCall('OneSignal#onUserStateChange', changeData),
77+
),
78+
(ByteData? data) {},
79+
);
80+
}
81+
4782
Future<dynamic> _handleMethod(MethodCall call) async {
4883
switch (call.method) {
4984
case "OneSignal#setAppId":
@@ -95,8 +130,17 @@ class OneSignalMockChannelController {
95130
(call.arguments as Map<dynamic, dynamic>)['language'] as String?;
96131
return {"success": true};
97132
case "OneSignal#requestPermission":
98-
state.locationPermissionRequested = true;
99-
break;
133+
// Location requestPermission (no arguments)
134+
if (call.arguments == null) {
135+
state.locationPermissionRequested = true;
136+
break;
137+
}
138+
// Notifications requestPermission (with fallbackToSettings argument)
139+
// Falls through to the notifications handler below
140+
state.requestPermissionCalled = true;
141+
state.requestPermissionFallbackToSettings = (call.arguments
142+
as Map<dynamic, dynamic>)['fallbackToSettings'] as bool?;
143+
return true;
100144
case "OneSignal#setShared":
101145
state.locationShared = call.arguments as bool?;
102146
break;
@@ -173,6 +217,101 @@ class OneSignalMockChannelController {
173217
state.preventedNotificationId = (call.arguments
174218
as Map<dynamic, dynamic>)['notificationId'] as String?;
175219
break;
220+
case "OneSignal#removeNotification":
221+
state.removedNotificationId =
222+
(call.arguments as Map<dynamic, dynamic>)['notificationId'] as int?;
223+
break;
224+
case "OneSignal#removeGroupedNotifications":
225+
state.removedNotificationGroup = (call.arguments
226+
as Map<dynamic, dynamic>)['notificationGroup'] as String?;
227+
break;
228+
case "OneSignal#clearAll":
229+
state.clearedAllNotifications = true;
230+
break;
231+
case "OneSignal#permission":
232+
return state.notificationPermission ?? false;
233+
case "OneSignal#permissionNative":
234+
return state.notificationPermissionNative ?? 1; // 1 = denied
235+
case "OneSignal#canRequest":
236+
return state.canRequestPermission ?? false;
237+
case "OneSignal#registerForProvisionalAuthorization":
238+
state.registerForProvisionalAuthorizationCalled = true;
239+
return true;
240+
case "OneSignal#addNativeClickListener":
241+
state.nativeClickListenerAdded = true;
242+
state.nativeClickListenerAddedCount++;
243+
break;
244+
case "OneSignal#proceedWithWillDisplay":
245+
state.proceedWithWillDisplayCalled = true;
246+
break;
247+
case "OneSignal#pushSubscriptionToken":
248+
return state.pushSubscriptionToken;
249+
case "OneSignal#pushSubscriptionId":
250+
return state.pushSubscriptionId;
251+
case "OneSignal#pushSubscriptionOptedIn":
252+
return state.pushSubscriptionOptedIn;
253+
case "OneSignal#optIn":
254+
state.pushSubscriptionOptInCalled = true;
255+
state.pushSubscriptionOptInCallCount++;
256+
break;
257+
case "OneSignal#optOut":
258+
state.pushSubscriptionOptOutCalled = true;
259+
state.pushSubscriptionOptOutCallCount++;
260+
break;
261+
case "OneSignal#addOutcome":
262+
state.addedOutcome = call.arguments as String;
263+
state.addOutcomeCallCount++;
264+
break;
265+
case "OneSignal#addUniqueOutcome":
266+
state.addedUniqueOutcome = call.arguments as String;
267+
state.addUniqueOutcomeCallCount++;
268+
break;
269+
case "OneSignal#addOutcomeWithValue":
270+
final args = call.arguments as Map<dynamic, dynamic>;
271+
state.addedOutcomeWithValueName = args['outcome_name'] as String;
272+
state.addedOutcomeWithValueValue = args['outcome_value'] as double;
273+
state.addOutcomeWithValueCallCount++;
274+
break;
275+
case "OneSignal#setLanguage":
276+
state.language =
277+
(call.arguments as Map<dynamic, dynamic>)['language'] as String?;
278+
break;
279+
case "OneSignal#addAliases":
280+
state.aliases = call.arguments as Map<dynamic, dynamic>?;
281+
break;
282+
case "OneSignal#removeAliases":
283+
state.removedAliases = call.arguments as List<dynamic>?;
284+
break;
285+
case "OneSignal#addTags":
286+
state.tags = call.arguments as Map<dynamic, dynamic>?;
287+
break;
288+
case "OneSignal#removeTags":
289+
state.deleteTags = call.arguments as List<dynamic>?;
290+
break;
291+
case "OneSignal#getTags":
292+
return state.tags ?? {};
293+
case "OneSignal#addEmail":
294+
state.addedEmail = call.arguments as String?;
295+
break;
296+
case "OneSignal#removeEmail":
297+
state.removedEmail = call.arguments as String?;
298+
break;
299+
case "OneSignal#addSms":
300+
state.addedSms = call.arguments as String?;
301+
break;
302+
case "OneSignal#removeSms":
303+
state.removedSms = call.arguments as String?;
304+
break;
305+
case "OneSignal#getExternalId":
306+
return state.externalId;
307+
case "OneSignal#getOnesignalId":
308+
return state.onesignalId;
309+
case "OneSignal#lifecycleInit":
310+
// Could be from user, inappmessages, or pushsubscription
311+
// We'll track both
312+
state.lifecycleInitCalled = true;
313+
state.userLifecycleInitCalled = true;
314+
break;
176315
}
177316
}
178317
}
@@ -233,6 +372,47 @@ class OneSignalState {
233372
Map<dynamic, dynamic>? postNotificationJson;
234373
String? displayedNotificationId;
235374
String? preventedNotificationId;
375+
int? removedNotificationId;
376+
String? removedNotificationGroup;
377+
bool? clearedAllNotifications;
378+
bool? notificationPermission;
379+
int?
380+
notificationPermissionNative; // 0 = notDetermined, 1 = denied, 2 = authorized, etc.
381+
bool? canRequestPermission;
382+
bool? requestPermissionCalled;
383+
bool? requestPermissionFallbackToSettings;
384+
bool? registerForProvisionalAuthorizationCalled;
385+
bool? nativeClickListenerAdded;
386+
int nativeClickListenerAddedCount = 0;
387+
bool? proceedWithWillDisplayCalled;
388+
389+
// push subscription
390+
String? pushSubscriptionId;
391+
String? pushSubscriptionToken;
392+
bool? pushSubscriptionOptedIn;
393+
bool pushSubscriptionOptInCalled = false;
394+
bool pushSubscriptionOptOutCalled = false;
395+
int pushSubscriptionOptInCallCount = 0;
396+
int pushSubscriptionOptOutCallCount = 0;
397+
398+
// session outcomes
399+
String? addedOutcome;
400+
int addOutcomeCallCount = 0;
401+
String? addedUniqueOutcome;
402+
int addUniqueOutcomeCallCount = 0;
403+
String? addedOutcomeWithValueName;
404+
double? addedOutcomeWithValueValue;
405+
int addOutcomeWithValueCallCount = 0;
406+
407+
// user
408+
String? onesignalId;
409+
Map<dynamic, dynamic>? aliases;
410+
List<dynamic>? removedAliases;
411+
String? addedEmail;
412+
String? removedEmail;
413+
String? addedSms;
414+
String? removedSms;
415+
bool? userLifecycleInitCalled;
236416

237417
/*
238418
All of the following functions parse the MethodCall

0 commit comments

Comments
 (0)