From b79d9b1efa2c8520aea471812c5516b45623e956 Mon Sep 17 00:00:00 2001 From: Kirk Morrow <9563562+kirkmorrow@users.noreply.github.com> Date: Tue, 2 Dec 2025 09:28:44 -0600 Subject: [PATCH 1/3] Add ethernet to ParseConnectivityResult Provides better alignment with newer version of connectivity_plus Add basic testing Part 1 of 2 to fix Issue #1042 --- .../lib/src/network/parse_connectivity.dart | 3 + .../src/network/parse_live_query_test.dart | 161 ++++++++++++++++++ 2 files changed, 164 insertions(+) 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..9eb146d1 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,141 @@ void main() { // 10 millisecond hold for stream await Future.delayed(Duration(milliseconds: 10)); }); + + group('Connectivity handling', () { + late MockConnectivityProvider mockConnectivity; + + setUp(() { + mockConnectivity = MockConnectivityProvider(); + }); + + tearDown(() { + mockConnectivity.dispose(); + }); + + test('should handle wifi connectivity', () async { + // arrange + mockConnectivity.setConnectivity(ParseConnectivityResult.wifi); + + await Parse().initialize( + 'appId', + serverUrl, + debug: true, + fileDirectory: 'someDirectory', + appName: 'appName', + appPackageName: 'somePackageName', + appVersion: 'someAppVersion', + connectivityProvider: mockConnectivity, + ); + + // act + final result = await mockConnectivity.checkConnectivity(); + + // assert + expect(result, ParseConnectivityResult.wifi); + }); + + test('should handle ethernet connectivity', () async { + // arrange + mockConnectivity.setConnectivity(ParseConnectivityResult.ethernet); + + await Parse().initialize( + 'appId', + serverUrl, + debug: true, + fileDirectory: 'someDirectory', + appName: 'appName', + appPackageName: 'somePackageName', + appVersion: 'someAppVersion', + connectivityProvider: mockConnectivity, + ); + + // act + final result = await mockConnectivity.checkConnectivity(); + + // assert + expect(result, ParseConnectivityResult.ethernet); + }); + + test('should handle mobile connectivity', () async { + // arrange + mockConnectivity.setConnectivity(ParseConnectivityResult.mobile); + + await Parse().initialize( + 'appId', + serverUrl, + debug: true, + fileDirectory: 'someDirectory', + appName: 'appName', + appPackageName: 'somePackageName', + appVersion: 'someAppVersion', + connectivityProvider: mockConnectivity, + ); + + // act + final result = await mockConnectivity.checkConnectivity(); + + // assert + expect(result, ParseConnectivityResult.mobile); + }); + + test('should handle no connectivity', () async { + // arrange + mockConnectivity.setConnectivity(ParseConnectivityResult.none); + + await Parse().initialize( + 'appId', + serverUrl, + debug: true, + fileDirectory: 'someDirectory', + appName: 'appName', + appPackageName: 'somePackageName', + appVersion: 'someAppVersion', + connectivityProvider: mockConnectivity, + ); + + // act + final result = await mockConnectivity.checkConnectivity(); + + // assert + expect(result, ParseConnectivityResult.none); + }); + + test('should emit connectivity changes through stream', () async { + // arrange + mockConnectivity.setConnectivity(ParseConnectivityResult.wifi); + + await Parse().initialize( + 'appId', + serverUrl, + debug: true, + fileDirectory: 'someDirectory', + appName: 'appName', + appPackageName: 'somePackageName', + appVersion: 'someAppVersion', + connectivityProvider: mockConnectivity, + ); + + final List emittedStates = []; + final subscription = mockConnectivity.connectivityStream.listen((state) { + emittedStates.add(state); + }); + + // act + 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 + expect(emittedStates.length, 3); + expect(emittedStates[0], ParseConnectivityResult.ethernet); + expect(emittedStates[1], ParseConnectivityResult.mobile); + expect(emittedStates[2], ParseConnectivityResult.none); + + await subscription.cancel(); + }); + }); } From 69d65fe24e22d233bb4203899a847835aa65001c Mon Sep 17 00:00:00 2001 From: Kirk Morrow <9563562+kirkmorrow@users.noreply.github.com> Date: Tue, 2 Dec 2025 09:50:14 -0600 Subject: [PATCH 2/3] Update packages/dart/test/src/network/parse_live_query_test.dart Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../src/network/parse_live_query_test.dart | 104 +++++++----------- 1 file changed, 38 insertions(+), 66 deletions(-) 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 9eb146d1..7f22e6a0 100644 --- a/packages/dart/test/src/network/parse_live_query_test.dart +++ b/packages/dart/test/src/network/parse_live_query_test.dart @@ -120,72 +120,44 @@ void main() { expect(result, ParseConnectivityResult.wifi); }); - test('should handle ethernet connectivity', () async { - // arrange - mockConnectivity.setConnectivity(ParseConnectivityResult.ethernet); - - await Parse().initialize( - 'appId', - serverUrl, - debug: true, - fileDirectory: 'someDirectory', - appName: 'appName', - appPackageName: 'somePackageName', - appVersion: 'someAppVersion', - connectivityProvider: mockConnectivity, - ); - - // act - final result = await mockConnectivity.checkConnectivity(); - - // assert - expect(result, ParseConnectivityResult.ethernet); - }); - - test('should handle mobile connectivity', () async { - // arrange - mockConnectivity.setConnectivity(ParseConnectivityResult.mobile); - - await Parse().initialize( - 'appId', - serverUrl, - debug: true, - fileDirectory: 'someDirectory', - appName: 'appName', - appPackageName: 'somePackageName', - appVersion: 'someAppVersion', - connectivityProvider: mockConnectivity, - ); - - // act - final result = await mockConnectivity.checkConnectivity(); - - // assert - expect(result, ParseConnectivityResult.mobile); - }); - - test('should handle no connectivity', () async { - // arrange - mockConnectivity.setConnectivity(ParseConnectivityResult.none); - - await Parse().initialize( - 'appId', - serverUrl, - debug: true, - fileDirectory: 'someDirectory', - appName: 'appName', - appPackageName: 'somePackageName', - appVersion: 'someAppVersion', - connectivityProvider: mockConnectivity, - ); - - // act - final result = await mockConnectivity.checkConnectivity(); - - // assert - expect(result, ParseConnectivityResult.none); - }); - + final connectivityCases = >[ + { + 'desc': 'ethernet', + 'state': ParseConnectivityResult.ethernet, + }, + { + 'desc': 'mobile', + 'state': ParseConnectivityResult.mobile, + }, + { + 'desc': 'none', + 'state': ParseConnectivityResult.none, + }, + ]; + + for (final testCase in connectivityCases) { + test('should handle ${testCase['desc']} connectivity', () async { + // arrange + mockConnectivity.setConnectivity(testCase['state']); + + await Parse().initialize( + 'appId', + serverUrl, + debug: true, + fileDirectory: 'someDirectory', + appName: 'appName', + appPackageName: 'somePackageName', + appVersion: 'someAppVersion', + connectivityProvider: mockConnectivity, + ); + + // act + final result = await mockConnectivity.checkConnectivity(); + + // assert + expect(result, testCase['state']); + }); + } test('should emit connectivity changes through stream', () async { // arrange mockConnectivity.setConnectivity(ParseConnectivityResult.wifi); From 312926cb9877917e95e0a8f9529eddbed6a6e1e5 Mon Sep 17 00:00:00 2001 From: Kirk Morrow <9563562+kirkmorrow@users.noreply.github.com> Date: Tue, 2 Dec 2025 10:03:18 -0600 Subject: [PATCH 3/3] Test fixes based on PR feedback --- .../src/network/parse_live_query_test.dart | 125 ++++++++++-------- 1 file changed, 68 insertions(+), 57 deletions(-) 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 7f22e6a0..b98a3483 100644 --- a/packages/dart/test/src/network/parse_live_query_test.dart +++ b/packages/dart/test/src/network/parse_live_query_test.dart @@ -90,95 +90,76 @@ void main() { group('Connectivity handling', () { late MockConnectivityProvider mockConnectivity; - setUp(() { + // Initialize once with mock provider, then test state changes + setUpAll(() async { mockConnectivity = MockConnectivityProvider(); - }); - - tearDown(() { - mockConnectivity.dispose(); - }); - - test('should handle wifi connectivity', () async { - // arrange - mockConnectivity.setConnectivity(ParseConnectivityResult.wifi); - + // Initialize Parse once with the mock provider await Parse().initialize( 'appId', serverUrl, - debug: true, + debug: false, fileDirectory: 'someDirectory', appName: 'appName', appPackageName: 'somePackageName', appVersion: 'someAppVersion', connectivityProvider: mockConnectivity, ); + }); - // act - final result = await mockConnectivity.checkConnectivity(); - - // assert - expect(result, ParseConnectivityResult.wifi); + tearDownAll(() { + mockConnectivity.dispose(); }); - final connectivityCases = >[ + // Test data for parameterized connectivity state tests + final connectivityTestCases = >[ + { + 'state': ParseConnectivityResult.wifi, + 'isOnline': true, + 'description': 'wifi should be treated as online', + }, { - 'desc': 'ethernet', 'state': ParseConnectivityResult.ethernet, + 'isOnline': true, + 'description': 'ethernet should be treated as online', }, { - 'desc': 'mobile', 'state': ParseConnectivityResult.mobile, + 'isOnline': true, + 'description': 'mobile should be treated as online', }, { - 'desc': 'none', 'state': ParseConnectivityResult.none, + 'isOnline': false, + 'description': 'none should be treated as offline', }, ]; - for (final testCase in connectivityCases) { - test('should handle ${testCase['desc']} connectivity', () async { + for (final testCase in connectivityTestCases) { + test(testCase['description'], () async { // arrange - mockConnectivity.setConnectivity(testCase['state']); - - await Parse().initialize( - 'appId', - serverUrl, - debug: true, - fileDirectory: 'someDirectory', - appName: 'appName', - appPackageName: 'somePackageName', - appVersion: 'someAppVersion', - connectivityProvider: mockConnectivity, - ); + final state = testCase['state'] as ParseConnectivityResult; + final isOnline = testCase['isOnline'] as bool; // act + mockConnectivity.setConnectivity(state); final result = await mockConnectivity.checkConnectivity(); - // assert - expect(result, testCase['state']); + // assert - verify the state is correctly identified + expect(result, state); + expect(result != ParseConnectivityResult.none, isOnline); }); } - test('should emit connectivity changes through stream', () async { - // arrange - mockConnectivity.setConnectivity(ParseConnectivityResult.wifi); - await Parse().initialize( - 'appId', - serverUrl, - debug: true, - fileDirectory: 'someDirectory', - appName: 'appName', - appPackageName: 'somePackageName', - appVersion: 'someAppVersion', - connectivityProvider: mockConnectivity, - ); - - final List emittedStates = []; + test('should emit connectivity state transitions through stream', () async { + // arrange + final emittedStates = []; final subscription = mockConnectivity.connectivityStream.listen((state) { emittedStates.add(state); }); - // act + // 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); @@ -186,11 +167,41 @@ void main() { 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(emittedStates.length, 3); - expect(emittedStates[0], ParseConnectivityResult.ethernet); - expect(emittedStates[1], ParseConnectivityResult.mobile); - expect(emittedStates[2], ParseConnectivityResult.none); + 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(); });