Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 72feefd

Browse files
authored
[connectivity_for_web] Migration to null-safety. (#3652)
1 parent a6cbf67 commit 72feefd

18 files changed

+219
-110
lines changed

packages/connectivity/connectivity_for_web/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.4.0
2+
3+
* Migrate to null-safety
4+
* Run tests using flutter driver
5+
16
## 0.3.1+4
27

38
* Remove unused `test` dependency.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Testing
2+
3+
This package utilizes the `integration_test` package to run its tests in a web browser.
4+
5+
See [flutter.dev > Integration testing](https://flutter.dev/docs/testing/integration-tests) for more info.
6+
7+
## Running the tests
8+
9+
Make sure you have updated to the latest Flutter master.
10+
11+
1. Check what version of Chrome is running on the machine you're running tests on.
12+
13+
2. Download and install driver for that version from here:
14+
* <https://chromedriver.chromium.org/downloads>
15+
16+
3. Start the driver using `chromedriver --port=4444`
17+
18+
4. Run tests: `flutter drive -d web-server --browser-name=chrome --driver=test_driver/integration_driver.dart --target=integration_test/TEST_NAME.dart`, or (in Linux):
19+
20+
* Single: `./run_test.sh integration_test/TEST_NAME.dart`
21+
* All: `./run_test.sh`
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
import 'package:integration_test/integration_test.dart';
2-
import 'package:flutter_test/flutter_test.dart';
3-
import 'package:connectivity_platform_interface/connectivity_platform_interface.dart';
41
import 'package:connectivity_for_web/src/network_information_api_connectivity_plugin.dart';
5-
6-
import 'package:mockito/mockito.dart';
2+
import 'package:connectivity_platform_interface/connectivity_platform_interface.dart';
3+
import 'package:flutter_test/flutter_test.dart';
4+
import 'package:integration_test/integration_test.dart';
75

86
import 'src/connectivity_mocks.dart';
97

@@ -12,66 +10,70 @@ void main() {
1210

1311
group('checkConnectivity', () {
1412
void testCheckConnectivity({
15-
String type,
16-
String effectiveType,
17-
num downlink = 10,
18-
num rtt = 50,
19-
ConnectivityResult expected,
13+
String? type,
14+
String? effectiveType,
15+
num? downlink = 10,
16+
int? rtt = 50,
17+
required ConnectivityResult expected,
2018
}) {
21-
final connection = MockNetworkInformation();
22-
when(connection.type).thenReturn(type);
23-
when(connection.effectiveType).thenReturn(effectiveType);
24-
when(connection.downlink).thenReturn(downlink);
25-
when(connection.rtt).thenReturn(downlink);
19+
final connection = FakeNetworkInformation(
20+
type: type,
21+
effectiveType: effectiveType,
22+
downlink: downlink,
23+
rtt: rtt,
24+
);
2625

2726
NetworkInformationApiConnectivityPlugin plugin =
2827
NetworkInformationApiConnectivityPlugin.withConnection(connection);
2928
expect(plugin.checkConnectivity(), completion(equals(expected)));
3029
}
3130

32-
test('0 downlink and rtt -> none', () {
31+
testWidgets('0 downlink and rtt -> none', (WidgetTester tester) async {
3332
testCheckConnectivity(
3433
effectiveType: '4g',
3534
downlink: 0,
3635
rtt: 0,
3736
expected: ConnectivityResult.none);
3837
});
39-
test('slow-2g -> mobile', () {
38+
testWidgets('slow-2g -> mobile', (WidgetTester tester) async {
4039
testCheckConnectivity(
4140
effectiveType: 'slow-2g', expected: ConnectivityResult.mobile);
4241
});
43-
test('2g -> mobile', () {
42+
testWidgets('2g -> mobile', (WidgetTester tester) async {
4443
testCheckConnectivity(
4544
effectiveType: '2g', expected: ConnectivityResult.mobile);
4645
});
47-
test('3g -> mobile', () {
46+
testWidgets('3g -> mobile', (WidgetTester tester) async {
4847
testCheckConnectivity(
4948
effectiveType: '3g', expected: ConnectivityResult.mobile);
5049
});
51-
test('4g -> wifi', () {
50+
testWidgets('4g -> wifi', (WidgetTester tester) async {
5251
testCheckConnectivity(
5352
effectiveType: '4g', expected: ConnectivityResult.wifi);
5453
});
5554
});
5655

5756
group('get onConnectivityChanged', () {
58-
test('puts change events in a Stream', () async {
59-
final connection = MockNetworkInformation();
57+
testWidgets('puts change events in a Stream', (WidgetTester tester) async {
58+
final connection = FakeNetworkInformation();
6059
NetworkInformationApiConnectivityPlugin plugin =
6160
NetworkInformationApiConnectivityPlugin.withConnection(connection);
6261

63-
Stream<ConnectivityResult> results = plugin.onConnectivityChanged;
62+
// The onConnectivityChanged stream is infinite, so we only .take(2) so the test completes.
63+
// We need to do .toList() now, because otherwise the Stream won't be actually listened to,
64+
// and we'll miss the calls to mockChangeValue below.
65+
final results = plugin.onConnectivityChanged.take(2).toList();
6466

6567
// Fake a disconnect-reconnect
6668
await connection.mockChangeValue(downlink: 0, rtt: 0);
6769
await connection.mockChangeValue(
6870
downlink: 10, rtt: 50, effectiveType: '4g');
6971

70-
// The stream of results is infinite, so we need to .take(2) for this test to complete.
72+
// Expect to see the disconnect-reconnect in the resulting stream.
7173
expect(
72-
results.take(2).toList(),
73-
completion(
74-
equals([ConnectivityResult.none, ConnectivityResult.wifi])));
74+
results,
75+
completion([ConnectivityResult.none, ConnectivityResult.wifi]),
76+
);
7577
});
7678
});
7779
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import 'dart:async';
2+
import 'dart:html';
3+
import 'dart:js_util' show getProperty;
4+
5+
import 'package:flutter_test/flutter_test.dart';
6+
7+
/// A Fake implementation of the NetworkInformation API that allows
8+
/// for external modification of its values.
9+
///
10+
/// Note that the DOM API works by internally mutating and broadcasting
11+
/// 'change' events.
12+
class FakeNetworkInformation extends Fake implements NetworkInformation {
13+
String? _type;
14+
String? _effectiveType;
15+
num? _downlink;
16+
int? _rtt;
17+
18+
@override
19+
String? get type => _type;
20+
21+
@override
22+
String? get effectiveType => _effectiveType;
23+
24+
@override
25+
num? get downlink => _downlink;
26+
27+
@override
28+
int? get rtt => _rtt;
29+
30+
FakeNetworkInformation({
31+
String? type,
32+
String? effectiveType,
33+
num? downlink,
34+
int? rtt,
35+
}) : this._type = type,
36+
this._effectiveType = effectiveType,
37+
this._downlink = downlink,
38+
this._rtt = rtt;
39+
40+
/// Changes the desired values, and triggers the change event listener.
41+
Future<void> mockChangeValue({
42+
String? type,
43+
String? effectiveType,
44+
num? downlink,
45+
int? rtt,
46+
}) async {
47+
this._type = type;
48+
this._effectiveType = effectiveType;
49+
this._downlink = downlink;
50+
this._rtt = rtt;
51+
52+
// This is set by the onConnectivityChanged getter...
53+
final Function onchange = getProperty(this, 'onchange') as Function;
54+
onchange(Event('change'));
55+
}
56+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/material.dart';
6+
7+
void main() {
8+
runApp(MyApp());
9+
}
10+
11+
/// App for testing
12+
class MyApp extends StatefulWidget {
13+
@override
14+
_MyAppState createState() => _MyAppState();
15+
}
16+
17+
class _MyAppState extends State<MyApp> {
18+
@override
19+
Widget build(BuildContext context) {
20+
return Directionality(
21+
textDirection: TextDirection.ltr,
22+
child: Text('Testing... Look at the console output for results!'),
23+
);
24+
}
25+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: connectivity_for_web_integration_tests
2+
publish_to: none
3+
4+
dependencies:
5+
connectivity_for_web:
6+
path: ../
7+
flutter:
8+
sdk: flutter
9+
10+
dev_dependencies:
11+
js: ^0.6.3
12+
flutter_test:
13+
sdk: flutter
14+
flutter_driver:
15+
sdk: flutter
16+
integration_test:
17+
sdk: flutter
18+
19+
environment:
20+
sdk: ">=2.12.0-259.9.beta <3.0.0"
21+
flutter: ">=1.27.0-0" # For integration_test from sdk
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/bash
2+
if pgrep -lf chromedriver > /dev/null; then
3+
echo "chromedriver is running."
4+
5+
if [ $# -eq 0 ]; then
6+
echo "No target specified, running all tests..."
7+
find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target='{}'
8+
else
9+
echo "Running test target: $1..."
10+
set -x
11+
flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target=$1
12+
fi
13+
14+
else
15+
echo "chromedriver is not running."
16+
echo "Please, check the README.md for instructions on how to use run_test.sh"
17+
fi
18+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright 2019 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:integration_test/integration_test_driver.dart';
6+
7+
Future<void> main() async => integrationDriver();

packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,26 @@ class DartHtmlConnectivityPlugin extends ConnectivityPlugin {
99
/// Checks the connection status of the device.
1010
@override
1111
Future<ConnectivityResult> checkConnectivity() async {
12-
return html.window.navigator.onLine
12+
return html.window.navigator.onLine ?? false
1313
? ConnectivityResult.wifi
1414
: ConnectivityResult.none;
1515
}
1616

17-
StreamController<ConnectivityResult> _connectivityResult;
17+
StreamController<ConnectivityResult>? _connectivityResult;
1818

1919
/// Returns a Stream of ConnectivityResults changes.
2020
@override
2121
Stream<ConnectivityResult> get onConnectivityChanged {
2222
if (_connectivityResult == null) {
23-
_connectivityResult = StreamController<ConnectivityResult>();
23+
_connectivityResult = StreamController<ConnectivityResult>.broadcast();
2424
// Fallback to dart:html window.onOnline / window.onOffline
2525
html.window.onOnline.listen((event) {
26-
_connectivityResult.add(ConnectivityResult.wifi);
26+
_connectivityResult!.add(ConnectivityResult.wifi);
2727
});
2828
html.window.onOffline.listen((event) {
29-
_connectivityResult.add(ConnectivityResult.none);
29+
_connectivityResult!.add(ConnectivityResult.none);
3030
});
3131
}
32-
return _connectivityResult.stream;
32+
return _connectivityResult!.stream;
3333
}
3434
}

packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'dart:async';
22
import 'dart:html' as html show window, NetworkInformation;
3-
import 'dart:js';
4-
import 'dart:js_util';
3+
import 'dart:js' show allowInterop;
4+
import 'dart:js_util' show setProperty;
55

66
import 'package:connectivity_platform_interface/connectivity_platform_interface.dart';
77
import 'package:connectivity_for_web/connectivity_for_web.dart';
@@ -18,7 +18,7 @@ class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin {
1818

1919
/// The constructor of the plugin.
2020
NetworkInformationApiConnectivityPlugin()
21-
: this.withConnection(html.window.navigator.connection);
21+
: this.withConnection(html.window.navigator.connection!);
2222

2323
/// Creates the plugin, with an override of the NetworkInformation object.
2424
@visibleForTesting
@@ -32,17 +32,19 @@ class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin {
3232
return networkInformationToConnectivityResult(_networkInformation);
3333
}
3434

35-
StreamController<ConnectivityResult> _connectivityResultStreamController;
36-
Stream<ConnectivityResult> _connectivityResultStream;
35+
StreamController<ConnectivityResult>? _connectivityResultStreamController;
36+
late Stream<ConnectivityResult> _connectivityResultStream;
3737

3838
/// Returns a Stream of ConnectivityResults changes.
3939
@override
4040
Stream<ConnectivityResult> get onConnectivityChanged {
4141
if (_connectivityResultStreamController == null) {
4242
_connectivityResultStreamController =
4343
StreamController<ConnectivityResult>();
44+
45+
// Directly write the 'onchange' function on the networkInformation object.
4446
setProperty(_networkInformation, 'onchange', allowInterop((_) {
45-
_connectivityResultStreamController
47+
_connectivityResultStreamController!
4648
.add(networkInformationToConnectivityResult(_networkInformation));
4749
}));
4850
// TODO: Implement the above with _networkInformation.onChange:
@@ -54,7 +56,7 @@ class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin {
5456
// onChange Stream upon hot restart.
5557
// https://github.com/dart-lang/sdk/issues/42679
5658
_connectivityResultStream =
57-
_connectivityResultStreamController.stream.asBroadcastStream();
59+
_connectivityResultStreamController!.stream.asBroadcastStream();
5860
}
5961
return _connectivityResultStream;
6062
}

packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import 'package:connectivity_platform_interface/connectivity_platform_interface.
33

44
/// Converts an incoming NetworkInformation object into the correct ConnectivityResult.
55
ConnectivityResult networkInformationToConnectivityResult(
6-
html.NetworkInformation info,
6+
html.NetworkInformation? info,
77
) {
88
if (info == null) {
99
return ConnectivityResult.none;
@@ -12,10 +12,10 @@ ConnectivityResult networkInformationToConnectivityResult(
1212
return ConnectivityResult.none;
1313
}
1414
if (info.effectiveType != null) {
15-
return _effectiveTypeToConnectivityResult(info.effectiveType);
15+
return _effectiveTypeToConnectivityResult(info.effectiveType!);
1616
}
1717
if (info.type != null) {
18-
return _typeToConnectivityResult(info.type);
18+
return _typeToConnectivityResult(info.type!);
1919
}
2020
return ConnectivityResult.none;
2121
}

0 commit comments

Comments
 (0)