diff --git a/packages/flutter/CHANGELOG.md b/packages/flutter/CHANGELOG.md index f7a334142..98b474036 100644 --- a/packages/flutter/CHANGELOG.md +++ b/packages/flutter/CHANGELOG.md @@ -1,3 +1,9 @@ +## [8.0.1](https://github.com/parse-community/Parse-SDK-Flutter/compare/flutter-8.0.0...flutter-8.0.1) (2024-07-27) + +### Bug Fixes + +* Conflict with version 6.x of `connectivity_plus` dependency ([#1002](https://github.com/parse-community/Parse-SDK-Flutter/pull/1002)) + ## [8.0.0](https://github.com/parse-community/Parse-SDK-Flutter/compare/flutter-7.0.0...flutter-8.0.0) (2024-05-15) ### BREAKING CHANGES diff --git a/packages/flutter/lib/parse_server_sdk_flutter.dart b/packages/flutter/lib/parse_server_sdk_flutter.dart index 33e4d8e79..fd25d510d 100644 --- a/packages/flutter/lib/parse_server_sdk_flutter.dart +++ b/packages/flutter/lib/parse_server_sdk_flutter.dart @@ -28,6 +28,11 @@ part 'src/push//parse_push.dart'; class Parse extends sdk.Parse with WidgetsBindingObserver implements sdk.ParseConnectivityProvider { + final Connectivity _connectivity; + + Parse([Connectivity? connectivity]) + : _connectivity = connectivity ?? Connectivity(); + /// To initialize Parse Server in your application /// /// This should be initialized in MyApp() creation @@ -107,31 +112,32 @@ class Parse extends sdk.Parse final StreamController _appResumedStreamController = StreamController(); + sdk.ParseConnectivityResult _mapConnectivityResults( + List connectivityResults) { + if (connectivityResults.contains(ConnectivityResult.none)) { + // ConnectivityPlus documentation says that if result is none there will only ever be one result and results + // will never be empty. So we can safely assume that if none is present, it is the only result. + return sdk.ParseConnectivityResult.none; + } else if (connectivityResults.contains(ConnectivityResult.wifi)) { + return sdk.ParseConnectivityResult.wifi; + } else if (connectivityResults.contains(ConnectivityResult.mobile)) { + return sdk.ParseConnectivityResult.mobile; + } else { + // anything else is considered wifi + return sdk.ParseConnectivityResult.wifi; + } + } + @override Future checkConnectivity() async { - switch (await Connectivity().checkConnectivity()) { - case ConnectivityResult.wifi: - return sdk.ParseConnectivityResult.wifi; - case ConnectivityResult.mobile: - return sdk.ParseConnectivityResult.mobile; - case ConnectivityResult.none: - return sdk.ParseConnectivityResult.none; - default: - return sdk.ParseConnectivityResult.wifi; - } + final connectivityResults = await _connectivity.checkConnectivity(); + return _mapConnectivityResults(connectivityResults); } @override Stream get connectivityStream { - return Connectivity().onConnectivityChanged.map((ConnectivityResult event) { - switch (event) { - case ConnectivityResult.wifi: - return sdk.ParseConnectivityResult.wifi; - case ConnectivityResult.mobile: - return sdk.ParseConnectivityResult.mobile; - default: - return sdk.ParseConnectivityResult.none; - } + return _connectivity.onConnectivityChanged.map((connectivityResults) { + return _mapConnectivityResults(connectivityResults); }); } diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 7a6453fdd..11507962a 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: parse_server_sdk_flutter description: The Flutter SDK to connect to Parse Server. Build your apps faster with Parse Platform, the complete application stack. -version: 8.0.0 +version: 8.0.1 homepage: https://parseplatform.org repository: https://github.com/parse-community/Parse-SDK-Flutter issue_tracker: https://github.com/parse-community/Parse-SDK-Flutter/issues @@ -31,7 +31,7 @@ dependencies: # path: ../dart # Networking - connectivity_plus: ^5.0.2 + connectivity_plus: ^6.0.3 #Database shared_preferences: ^2.2.2 diff --git a/packages/flutter/test/src/parse_server_sdk_flutter_test.dart b/packages/flutter/test/src/parse_server_sdk_flutter_test.dart new file mode 100644 index 000000000..0d3124d68 --- /dev/null +++ b/packages/flutter/test/src/parse_server_sdk_flutter_test.dart @@ -0,0 +1,178 @@ +@TestOn('dart-vm') +@Timeout.factor(2) + +import 'dart:async'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:parse_server_sdk_flutter/parse_server_sdk_flutter.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'storage/core_store_directory_io_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + late Parse parse; + late FakeConnectivity fakeConnectivity; + + setUp(() { + fakeConnectivity = FakeConnectivity(); + parse = Parse(fakeConnectivity); + + PackageInfo.setMockInitialValues( + appName: 'appName', + packageName: 'packageName', + version: '1.0', + buildNumber: '1', + buildSignature: 'buildSignature', + ); + SharedPreferences.setMockInitialValues({}); + PathProviderPlatform.instance = FakePathProviderPlatform(); + }); + + group('Connectivity static checks', () { + test('Check when connectivity is None', () async { + fakeConnectivity.addConnectivityStatus(ConnectivityResult.none); + + // sut + final result = await parse.checkConnectivity(); + + expect(result, ParseConnectivityResult.none); + }); + + test('Check when connectivity is Wifi', () async { + fakeConnectivity.addConnectivityStatus(ConnectivityResult.wifi); + + // sut + final result = await parse.checkConnectivity(); + + expect(result, ParseConnectivityResult.wifi); + }); + + test('Check when connectivity is Mobile', () async { + fakeConnectivity.addConnectivityStatus(ConnectivityResult.mobile); + + // sut + final result = await parse.checkConnectivity(); + + expect(result, ParseConnectivityResult.mobile); + }); + + test('Check when connectivity is Mobile and VPN', () async { + fakeConnectivity.addConnectivityStatus(ConnectivityResult.vpn); + fakeConnectivity.addConnectivityStatus(ConnectivityResult.mobile); + + // sut + final result = await parse.checkConnectivity(); + + expect(result, ParseConnectivityResult.mobile); + }); + + test('Check when connectivity is Wifi + Mobile that Wifi is preferred', + () async { + fakeConnectivity.addConnectivityStatus(ConnectivityResult.mobile); + fakeConnectivity.addConnectivityStatus(ConnectivityResult.wifi); + + // sut + final result = await parse.checkConnectivity(); + + expect(result, ParseConnectivityResult.wifi); + }); + + test( + 'Check when connectivity is Other that we preserve old behavior that Wifi is assumed', + () async { + fakeConnectivity.addConnectivityStatus(ConnectivityResult.other); + + // sut + final result = await parse.checkConnectivity(); + + expect(result, ParseConnectivityResult.wifi); + }); + }); + + group('Connectivity stream tests', () { + test('Update stream when connectivity changes to None', () async { + final completer = Completer(); + fakeConnectivity.addConnectivityStatus(ConnectivityResult.mobile); + parse.connectivityStream.listen((event) { + if (event == ParseConnectivityResult.none) { + completer.complete(event); + } + }); + + // sut - trigger event + fakeConnectivity.updateConnectivityStatus(ConnectivityResult.none); + final result = await completer.future; + + expect(result, ParseConnectivityResult.none); + }, timeout: const Timeout(Duration(seconds: 1))); + }); + + test('Update stream when connectivity changes to Wifi', () async { + final completer = Completer(); + fakeConnectivity.addConnectivityStatus(ConnectivityResult.none); + parse.connectivityStream.listen((event) { + if (event == ParseConnectivityResult.wifi) { + completer.complete(event); + } + }); + + // sut - trigger event + fakeConnectivity.updateConnectivityStatus(ConnectivityResult.wifi); + final result = await completer.future; + + expect(result, ParseConnectivityResult.wifi); + }, timeout: const Timeout(Duration(seconds: 1))); + + test( + 'Update stream when connectivity even though connectivity stayed the same', + () async { + final completer = Completer(); + fakeConnectivity.addConnectivityStatus(ConnectivityResult.mobile); + parse.connectivityStream.listen((event) { + if (event == ParseConnectivityResult.mobile) { + completer.complete(event); + } + }); + + // sut - trigger event where mobile user joins VPN + fakeConnectivity.addConnectivityStatus(ConnectivityResult.vpn); + final result = await completer.future; + + // assert that event was triggered but connectivity still says mobile + expect(result, ParseConnectivityResult.mobile); + }, timeout: const Timeout(Duration(seconds: 1))); +} + +Connectivity get fakeConnectivity { + return FakeConnectivity(); +} + +class FakeConnectivity extends Fake implements Connectivity { + final List _results = List.empty(growable: true); + final StreamController> _streamController = + StreamController.broadcast(); + + void updateConnectivityStatus(ConnectivityResult result) { + _results.clear(); + addConnectivityStatus(result); + } + + addConnectivityStatus(ConnectivityResult result) { + _results.add(result); + _streamController.sink.add(_results); + } + + @override + Future> checkConnectivity() async { + return _results; + } + + @override + Stream> get onConnectivityChanged { + return _streamController.stream; + } +}