diff --git a/packages/dart/lib/src/network/parse_connectivity.dart b/packages/dart/lib/src/network/parse_connectivity.dart index 0512f68f..7badbba2 100644 --- a/packages/dart/lib/src/network/parse_connectivity.dart +++ b/packages/dart/lib/src/network/parse_connectivity.dart @@ -5,6 +5,9 @@ enum ParseConnectivityResult { /// WiFi: Device connected via Wi-Fi wifi, + /// Ethernet: Device connected via Ethernet + ethernet, + /// Mobile: Device connected to cellular network mobile, diff --git a/packages/dart/test/src/network/parse_live_query_test.dart b/packages/dart/test/src/network/parse_live_query_test.dart index a6259be8..b98a3483 100644 --- a/packages/dart/test/src/network/parse_live_query_test.dart +++ b/packages/dart/test/src/network/parse_live_query_test.dart @@ -6,6 +6,30 @@ import 'package:test/test.dart'; import '../../test_utils.dart'; +/// Mock connectivity provider for testing different connectivity states +class MockConnectivityProvider implements ParseConnectivityProvider { + final StreamController _controller = + StreamController.broadcast(); + ParseConnectivityResult _currentState = ParseConnectivityResult.wifi; + + @override + Future checkConnectivity() async { + return _currentState; + } + + @override + Stream get connectivityStream => _controller.stream; + + void setConnectivity(ParseConnectivityResult state) { + _currentState = state; + _controller.add(state); + } + + void dispose() { + _controller.close(); + } +} + void main() { setUpAll(() async { // Create a fake server @@ -62,4 +86,124 @@ void main() { // 10 millisecond hold for stream await Future.delayed(Duration(milliseconds: 10)); }); + + group('Connectivity handling', () { + late MockConnectivityProvider mockConnectivity; + + // Initialize once with mock provider, then test state changes + setUpAll(() async { + mockConnectivity = MockConnectivityProvider(); + // Initialize Parse once with the mock provider + await Parse().initialize( + 'appId', + serverUrl, + debug: false, + fileDirectory: 'someDirectory', + appName: 'appName', + appPackageName: 'somePackageName', + appVersion: 'someAppVersion', + connectivityProvider: mockConnectivity, + ); + }); + + tearDownAll(() { + mockConnectivity.dispose(); + }); + + // Test data for parameterized connectivity state tests + final connectivityTestCases = >[ + { + 'state': ParseConnectivityResult.wifi, + 'isOnline': true, + 'description': 'wifi should be treated as online', + }, + { + 'state': ParseConnectivityResult.ethernet, + 'isOnline': true, + 'description': 'ethernet should be treated as online', + }, + { + 'state': ParseConnectivityResult.mobile, + 'isOnline': true, + 'description': 'mobile should be treated as online', + }, + { + 'state': ParseConnectivityResult.none, + 'isOnline': false, + 'description': 'none should be treated as offline', + }, + ]; + + for (final testCase in connectivityTestCases) { + test(testCase['description'], () async { + // arrange + final state = testCase['state'] as ParseConnectivityResult; + final isOnline = testCase['isOnline'] as bool; + + // act + mockConnectivity.setConnectivity(state); + final result = await mockConnectivity.checkConnectivity(); + + // assert - verify the state is correctly identified + expect(result, state); + expect(result != ParseConnectivityResult.none, isOnline); + }); + } + + test('should emit connectivity state transitions through stream', () async { + // arrange + final emittedStates = []; + final subscription = mockConnectivity.connectivityStream.listen((state) { + emittedStates.add(state); + }); + + // act - transition through different connectivity states + mockConnectivity.setConnectivity(ParseConnectivityResult.wifi); + await Future.delayed(Duration(milliseconds: 10)); + mockConnectivity.setConnectivity(ParseConnectivityResult.ethernet); + await Future.delayed(Duration(milliseconds: 10)); + mockConnectivity.setConnectivity(ParseConnectivityResult.mobile); + await Future.delayed(Duration(milliseconds: 10)); + mockConnectivity.setConnectivity(ParseConnectivityResult.none); + await Future.delayed(Duration(milliseconds: 10)); + + // assert - all state changes should be emitted + expect(emittedStates.length, 4); + expect(emittedStates[0], ParseConnectivityResult.wifi); + expect(emittedStates[1], ParseConnectivityResult.ethernet); + expect(emittedStates[2], ParseConnectivityResult.mobile); + expect(emittedStates[3], ParseConnectivityResult.none); + + // verify online states (wifi, ethernet, mobile) are not "none" + expect(emittedStates[0], isNot(ParseConnectivityResult.none)); + expect(emittedStates[1], isNot(ParseConnectivityResult.none)); + expect(emittedStates[2], isNot(ParseConnectivityResult.none)); + + await subscription.cancel(); + }); + + test('should transition from offline to online correctly', () async { + // arrange + final stateChanges = []; + final subscription = mockConnectivity.connectivityStream.listen((state) { + stateChanges.add(state); + }); + + // act - start offline, then go online via ethernet + mockConnectivity.setConnectivity(ParseConnectivityResult.none); + await Future.delayed(Duration(milliseconds: 10)); + mockConnectivity.setConnectivity(ParseConnectivityResult.ethernet); + await Future.delayed(Duration(milliseconds: 10)); + + // assert + expect(stateChanges.length, 2); + expect(stateChanges[0], ParseConnectivityResult.none); + expect(stateChanges[1], ParseConnectivityResult.ethernet); + // Verify the transition is from offline to online + expect(stateChanges[0] == ParseConnectivityResult.none, true); + expect(stateChanges[1] != ParseConnectivityResult.none, true); + + await subscription.cancel(); + }); + }); }