Skip to content

Commit 60520d6

Browse files
authored
fix: LiveQuery not working due to ethernet not recognized as connectivity state (#1091)
1 parent 72899e9 commit 60520d6

File tree

3 files changed

+231
-18
lines changed

3 files changed

+231
-18
lines changed

packages/flutter/lib/parse_server_sdk_flutter.dart

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -116,32 +116,33 @@ class Parse extends sdk.Parse
116116
final StreamController<void> _appResumedStreamController =
117117
StreamController<void>();
118118

119-
@override
120-
Future<sdk.ParseConnectivityResult> checkConnectivity() async {
121-
List<ConnectivityResult> list = await Connectivity().checkConnectivity();
122-
123-
if (list.contains(ConnectivityResult.wifi)) {
119+
/// Maps connectivity_plus results to ParseConnectivityResult.
120+
///
121+
/// Priority: wifi > ethernet > mobile > none
122+
/// This ensures ethernet is treated as an online connection type.
123+
sdk.ParseConnectivityResult _mapConnectivity(
124+
List<ConnectivityResult> results,
125+
) {
126+
if (results.contains(ConnectivityResult.wifi)) {
124127
return sdk.ParseConnectivityResult.wifi;
125-
} else if (list.contains(ConnectivityResult.mobile)) {
128+
} else if (results.contains(ConnectivityResult.ethernet)) {
129+
return sdk.ParseConnectivityResult.ethernet;
130+
} else if (results.contains(ConnectivityResult.mobile)) {
126131
return sdk.ParseConnectivityResult.mobile;
127132
} else {
128133
return sdk.ParseConnectivityResult.none;
129134
}
130135
}
131136

137+
@override
138+
Future<sdk.ParseConnectivityResult> checkConnectivity() async {
139+
List<ConnectivityResult> list = await Connectivity().checkConnectivity();
140+
return _mapConnectivity(list);
141+
}
142+
132143
@override
133144
Stream<sdk.ParseConnectivityResult> get connectivityStream {
134-
return Connectivity().onConnectivityChanged.map((
135-
List<ConnectivityResult> event,
136-
) {
137-
if (event.contains(ConnectivityResult.wifi)) {
138-
return sdk.ParseConnectivityResult.wifi;
139-
} else if (event.contains(ConnectivityResult.mobile)) {
140-
return sdk.ParseConnectivityResult.mobile;
141-
} else {
142-
return sdk.ParseConnectivityResult.none;
143-
}
144-
});
145+
return Connectivity().onConnectivityChanged.map(_mapConnectivity);
145146
}
146147

147148
@override

packages/flutter/pubspec.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ dependencies:
2525
flutter:
2626
sdk: flutter
2727

28-
parse_server_sdk: ">=6.4.0 <10.0.0"
28+
parse_server_sdk: ">=9.4.2 <10.0.0"
2929
# Uncomment for local testing
3030
#parse_server_sdk:
3131
# path: ../dart
@@ -48,6 +48,7 @@ dev_dependencies:
4848
sdk: flutter
4949

5050
flutter_lints: ">=4.0.0 <7.0.0"
51+
connectivity_plus_platform_interface: ^2.0.0
5152
path_provider_platform_interface: ^2.1.2
5253
plugin_platform_interface: ^2.1.8
5354

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
import 'dart:async';
2+
3+
import 'package:connectivity_plus_platform_interface/connectivity_plus_platform_interface.dart';
4+
import 'package:flutter_test/flutter_test.dart';
5+
import 'package:parse_server_sdk_flutter/parse_server_sdk_flutter.dart';
6+
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
7+
8+
/// Mock implementation of ConnectivityPlatform for testing
9+
class MockConnectivityPlatform extends Fake
10+
with MockPlatformInterfaceMixin
11+
implements ConnectivityPlatform {
12+
List<ConnectivityResult> _connectivity = [ConnectivityResult.none];
13+
final StreamController<List<ConnectivityResult>> _controller =
14+
StreamController<List<ConnectivityResult>>.broadcast();
15+
16+
void setConnectivity(List<ConnectivityResult> connectivity) {
17+
_connectivity = connectivity;
18+
_controller.add(connectivity);
19+
}
20+
21+
@override
22+
Future<List<ConnectivityResult>> checkConnectivity() async {
23+
return _connectivity;
24+
}
25+
26+
@override
27+
Stream<List<ConnectivityResult>> get onConnectivityChanged =>
28+
_controller.stream;
29+
30+
void dispose() {
31+
_controller.close();
32+
}
33+
}
34+
35+
void main() {
36+
TestWidgetsFlutterBinding.ensureInitialized();
37+
38+
group('Parse.checkConnectivity() implementation', () {
39+
late MockConnectivityPlatform mockPlatform;
40+
41+
setUp(() {
42+
mockPlatform = MockConnectivityPlatform();
43+
ConnectivityPlatform.instance = mockPlatform;
44+
});
45+
46+
tearDown(() {
47+
mockPlatform.dispose();
48+
});
49+
50+
test('wifi connection returns ParseConnectivityResult.wifi', () async {
51+
mockPlatform.setConnectivity([ConnectivityResult.wifi]);
52+
53+
final result = await Parse().checkConnectivity();
54+
55+
expect(result, ParseConnectivityResult.wifi);
56+
});
57+
58+
test(
59+
'ethernet connection returns ParseConnectivityResult.ethernet',
60+
() async {
61+
mockPlatform.setConnectivity([ConnectivityResult.ethernet]);
62+
63+
final result = await Parse().checkConnectivity();
64+
65+
expect(result, ParseConnectivityResult.ethernet);
66+
},
67+
);
68+
69+
test('mobile connection returns ParseConnectivityResult.mobile', () async {
70+
mockPlatform.setConnectivity([ConnectivityResult.mobile]);
71+
72+
final result = await Parse().checkConnectivity();
73+
74+
expect(result, ParseConnectivityResult.mobile);
75+
});
76+
77+
test('no connection returns ParseConnectivityResult.none', () async {
78+
mockPlatform.setConnectivity([ConnectivityResult.none]);
79+
80+
final result = await Parse().checkConnectivity();
81+
82+
expect(result, ParseConnectivityResult.none);
83+
});
84+
85+
test('wifi takes priority over ethernet', () async {
86+
mockPlatform.setConnectivity([
87+
ConnectivityResult.wifi,
88+
ConnectivityResult.ethernet,
89+
]);
90+
91+
final result = await Parse().checkConnectivity();
92+
93+
expect(result, ParseConnectivityResult.wifi);
94+
});
95+
96+
test('ethernet takes priority over mobile (issue #1042 fix)', () async {
97+
mockPlatform.setConnectivity([
98+
ConnectivityResult.ethernet,
99+
ConnectivityResult.mobile,
100+
]);
101+
102+
final result = await Parse().checkConnectivity();
103+
104+
expect(result, ParseConnectivityResult.ethernet);
105+
});
106+
107+
test('unsupported connection types fall back to none', () async {
108+
mockPlatform.setConnectivity([ConnectivityResult.bluetooth]);
109+
110+
final result = await Parse().checkConnectivity();
111+
112+
expect(result, ParseConnectivityResult.none);
113+
});
114+
});
115+
116+
group('Parse.connectivityStream implementation', () {
117+
late MockConnectivityPlatform mockPlatform;
118+
119+
setUp(() {
120+
mockPlatform = MockConnectivityPlatform();
121+
ConnectivityPlatform.instance = mockPlatform;
122+
});
123+
124+
tearDown(() {
125+
mockPlatform.dispose();
126+
});
127+
128+
test('wifi event emits ParseConnectivityResult.wifi', () async {
129+
final completer = Completer<ParseConnectivityResult>();
130+
final subscription = Parse().connectivityStream.listen((result) {
131+
if (!completer.isCompleted) {
132+
completer.complete(result);
133+
}
134+
});
135+
136+
mockPlatform.setConnectivity([ConnectivityResult.wifi]);
137+
138+
final result = await completer.future;
139+
expect(result, ParseConnectivityResult.wifi);
140+
141+
await subscription.cancel();
142+
});
143+
144+
test('ethernet event emits ParseConnectivityResult.ethernet', () async {
145+
final completer = Completer<ParseConnectivityResult>();
146+
final subscription = Parse().connectivityStream.listen((result) {
147+
if (!completer.isCompleted) {
148+
completer.complete(result);
149+
}
150+
});
151+
152+
mockPlatform.setConnectivity([ConnectivityResult.ethernet]);
153+
154+
final result = await completer.future;
155+
expect(result, ParseConnectivityResult.ethernet);
156+
157+
await subscription.cancel();
158+
});
159+
160+
test('mobile event emits ParseConnectivityResult.mobile', () async {
161+
final completer = Completer<ParseConnectivityResult>();
162+
final subscription = Parse().connectivityStream.listen((result) {
163+
if (!completer.isCompleted) {
164+
completer.complete(result);
165+
}
166+
});
167+
168+
mockPlatform.setConnectivity([ConnectivityResult.mobile]);
169+
170+
final result = await completer.future;
171+
expect(result, ParseConnectivityResult.mobile);
172+
173+
await subscription.cancel();
174+
});
175+
176+
test('none event emits ParseConnectivityResult.none', () async {
177+
final completer = Completer<ParseConnectivityResult>();
178+
final subscription = Parse().connectivityStream.listen((result) {
179+
if (!completer.isCompleted) {
180+
completer.complete(result);
181+
}
182+
});
183+
184+
mockPlatform.setConnectivity([ConnectivityResult.none]);
185+
186+
final result = await completer.future;
187+
expect(result, ParseConnectivityResult.none);
188+
189+
await subscription.cancel();
190+
});
191+
192+
test('stream respects priority: ethernet over mobile', () async {
193+
final completer = Completer<ParseConnectivityResult>();
194+
final subscription = Parse().connectivityStream.listen((result) {
195+
if (!completer.isCompleted) {
196+
completer.complete(result);
197+
}
198+
});
199+
200+
mockPlatform.setConnectivity([
201+
ConnectivityResult.ethernet,
202+
ConnectivityResult.mobile,
203+
]);
204+
205+
final result = await completer.future;
206+
expect(result, ParseConnectivityResult.ethernet);
207+
208+
await subscription.cancel();
209+
});
210+
});
211+
}

0 commit comments

Comments
 (0)