diff --git a/packages/connectivity/connectivity_for_web/CHANGELOG.md b/packages/connectivity/connectivity_for_web/CHANGELOG.md index f6d83dd3e0cc..ccd689760b84 100644 --- a/packages/connectivity/connectivity_for_web/CHANGELOG.md +++ b/packages/connectivity/connectivity_for_web/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.4.0 + +* Migrate to null-safety +* Run tests using flutter driver + ## 0.3.1+4 * Remove unused `test` dependency. diff --git a/packages/connectivity/connectivity_for_web/example/README.md b/packages/connectivity/connectivity_for_web/example/README.md new file mode 100644 index 000000000000..0ec01e025570 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/example/README.md @@ -0,0 +1,21 @@ +# Testing + +This package utilizes the `integration_test` package to run its tests in a web browser. + +See [flutter.dev > Integration testing](https://flutter.dev/docs/testing/integration-tests) for more info. + +## Running the tests + +Make sure you have updated to the latest Flutter master. + +1. Check what version of Chrome is running on the machine you're running tests on. + +2. Download and install driver for that version from here: + * + +3. Start the driver using `chromedriver --port=4444` + +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): + + * Single: `./run_test.sh integration_test/TEST_NAME.dart` + * All: `./run_test.sh` diff --git a/packages/connectivity/connectivity_for_web/test/lib/main.dart b/packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart similarity index 57% rename from packages/connectivity/connectivity_for_web/test/lib/main.dart rename to packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart index e3473532553e..f8e8059e7dba 100644 --- a/packages/connectivity/connectivity_for_web/test/lib/main.dart +++ b/packages/connectivity/connectivity_for_web/example/integration_test/network_information_test.dart @@ -1,9 +1,7 @@ -import 'package:integration_test/integration_test.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; import 'package:connectivity_for_web/src/network_information_api_connectivity_plugin.dart'; - -import 'package:mockito/mockito.dart'; +import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; import 'src/connectivity_mocks.dart'; @@ -12,66 +10,70 @@ void main() { group('checkConnectivity', () { void testCheckConnectivity({ - String type, - String effectiveType, - num downlink = 10, - num rtt = 50, - ConnectivityResult expected, + String? type, + String? effectiveType, + num? downlink = 10, + int? rtt = 50, + required ConnectivityResult expected, }) { - final connection = MockNetworkInformation(); - when(connection.type).thenReturn(type); - when(connection.effectiveType).thenReturn(effectiveType); - when(connection.downlink).thenReturn(downlink); - when(connection.rtt).thenReturn(downlink); + final connection = FakeNetworkInformation( + type: type, + effectiveType: effectiveType, + downlink: downlink, + rtt: rtt, + ); NetworkInformationApiConnectivityPlugin plugin = NetworkInformationApiConnectivityPlugin.withConnection(connection); expect(plugin.checkConnectivity(), completion(equals(expected))); } - test('0 downlink and rtt -> none', () { + testWidgets('0 downlink and rtt -> none', (WidgetTester tester) async { testCheckConnectivity( effectiveType: '4g', downlink: 0, rtt: 0, expected: ConnectivityResult.none); }); - test('slow-2g -> mobile', () { + testWidgets('slow-2g -> mobile', (WidgetTester tester) async { testCheckConnectivity( effectiveType: 'slow-2g', expected: ConnectivityResult.mobile); }); - test('2g -> mobile', () { + testWidgets('2g -> mobile', (WidgetTester tester) async { testCheckConnectivity( effectiveType: '2g', expected: ConnectivityResult.mobile); }); - test('3g -> mobile', () { + testWidgets('3g -> mobile', (WidgetTester tester) async { testCheckConnectivity( effectiveType: '3g', expected: ConnectivityResult.mobile); }); - test('4g -> wifi', () { + testWidgets('4g -> wifi', (WidgetTester tester) async { testCheckConnectivity( effectiveType: '4g', expected: ConnectivityResult.wifi); }); }); group('get onConnectivityChanged', () { - test('puts change events in a Stream', () async { - final connection = MockNetworkInformation(); + testWidgets('puts change events in a Stream', (WidgetTester tester) async { + final connection = FakeNetworkInformation(); NetworkInformationApiConnectivityPlugin plugin = NetworkInformationApiConnectivityPlugin.withConnection(connection); - Stream results = plugin.onConnectivityChanged; + // The onConnectivityChanged stream is infinite, so we only .take(2) so the test completes. + // We need to do .toList() now, because otherwise the Stream won't be actually listened to, + // and we'll miss the calls to mockChangeValue below. + final results = plugin.onConnectivityChanged.take(2).toList(); // Fake a disconnect-reconnect await connection.mockChangeValue(downlink: 0, rtt: 0); await connection.mockChangeValue( downlink: 10, rtt: 50, effectiveType: '4g'); - // The stream of results is infinite, so we need to .take(2) for this test to complete. + // Expect to see the disconnect-reconnect in the resulting stream. expect( - results.take(2).toList(), - completion( - equals([ConnectivityResult.none, ConnectivityResult.wifi]))); + results, + completion([ConnectivityResult.none, ConnectivityResult.wifi]), + ); }); }); } diff --git a/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart b/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart new file mode 100644 index 000000000000..fc795595e3f3 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/example/integration_test/src/connectivity_mocks.dart @@ -0,0 +1,56 @@ +import 'dart:async'; +import 'dart:html'; +import 'dart:js_util' show getProperty; + +import 'package:flutter_test/flutter_test.dart'; + +/// A Fake implementation of the NetworkInformation API that allows +/// for external modification of its values. +/// +/// Note that the DOM API works by internally mutating and broadcasting +/// 'change' events. +class FakeNetworkInformation extends Fake implements NetworkInformation { + String? _type; + String? _effectiveType; + num? _downlink; + int? _rtt; + + @override + String? get type => _type; + + @override + String? get effectiveType => _effectiveType; + + @override + num? get downlink => _downlink; + + @override + int? get rtt => _rtt; + + FakeNetworkInformation({ + String? type, + String? effectiveType, + num? downlink, + int? rtt, + }) : this._type = type, + this._effectiveType = effectiveType, + this._downlink = downlink, + this._rtt = rtt; + + /// Changes the desired values, and triggers the change event listener. + Future mockChangeValue({ + String? type, + String? effectiveType, + num? downlink, + int? rtt, + }) async { + this._type = type; + this._effectiveType = effectiveType; + this._downlink = downlink; + this._rtt = rtt; + + // This is set by the onConnectivityChanged getter... + final Function onchange = getProperty(this, 'onchange') as Function; + onchange(Event('change')); + } +} diff --git a/packages/connectivity/connectivity_for_web/example/lib/main.dart b/packages/connectivity/connectivity_for_web/example/lib/main.dart new file mode 100644 index 000000000000..e1a38dcdcd46 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/example/lib/main.dart @@ -0,0 +1,25 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +void main() { + runApp(MyApp()); +} + +/// App for testing +class MyApp extends StatefulWidget { + @override + _MyAppState createState() => _MyAppState(); +} + +class _MyAppState extends State { + @override + Widget build(BuildContext context) { + return Directionality( + textDirection: TextDirection.ltr, + child: Text('Testing... Look at the console output for results!'), + ); + } +} diff --git a/packages/connectivity/connectivity_for_web/example/pubspec.yaml b/packages/connectivity/connectivity_for_web/example/pubspec.yaml new file mode 100644 index 000000000000..54289bc648ec --- /dev/null +++ b/packages/connectivity/connectivity_for_web/example/pubspec.yaml @@ -0,0 +1,21 @@ +name: connectivity_for_web_integration_tests +publish_to: none + +dependencies: + connectivity_for_web: + path: ../ + flutter: + sdk: flutter + +dev_dependencies: + js: ^0.6.3 + flutter_test: + sdk: flutter + flutter_driver: + sdk: flutter + integration_test: + sdk: flutter + +environment: + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.27.0-0" # For integration_test from sdk diff --git a/packages/connectivity/connectivity_for_web/example/run_test.sh b/packages/connectivity/connectivity_for_web/example/run_test.sh new file mode 100755 index 000000000000..8e6f149358c9 --- /dev/null +++ b/packages/connectivity/connectivity_for_web/example/run_test.sh @@ -0,0 +1,18 @@ +#!/usr/bin/bash +if pgrep -lf chromedriver > /dev/null; then + echo "chromedriver is running." + + if [ $# -eq 0 ]; then + echo "No target specified, running all tests..." + 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='{}' + else + echo "Running test target: $1..." + set -x + flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_driver.dart --target=$1 + fi + + else + echo "chromedriver is not running." + echo "Please, check the README.md for instructions on how to use run_test.sh" +fi + diff --git a/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart b/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart new file mode 100644 index 000000000000..64e2248a4f9b --- /dev/null +++ b/packages/connectivity/connectivity_for_web/example/test_driver/integration_driver.dart @@ -0,0 +1,7 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:integration_test/integration_test_driver.dart'; + +Future main() async => integrationDriver(); diff --git a/packages/connectivity/connectivity_for_web/test/web/index.html b/packages/connectivity/connectivity_for_web/example/web/index.html similarity index 100% rename from packages/connectivity/connectivity_for_web/test/web/index.html rename to packages/connectivity/connectivity_for_web/example/web/index.html diff --git a/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart b/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart index 5caa5679d6ad..950d26804371 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/dart_html_connectivity_plugin.dart @@ -9,26 +9,26 @@ class DartHtmlConnectivityPlugin extends ConnectivityPlugin { /// Checks the connection status of the device. @override Future checkConnectivity() async { - return html.window.navigator.onLine + return html.window.navigator.onLine ?? false ? ConnectivityResult.wifi : ConnectivityResult.none; } - StreamController _connectivityResult; + StreamController? _connectivityResult; /// Returns a Stream of ConnectivityResults changes. @override Stream get onConnectivityChanged { if (_connectivityResult == null) { - _connectivityResult = StreamController(); + _connectivityResult = StreamController.broadcast(); // Fallback to dart:html window.onOnline / window.onOffline html.window.onOnline.listen((event) { - _connectivityResult.add(ConnectivityResult.wifi); + _connectivityResult!.add(ConnectivityResult.wifi); }); html.window.onOffline.listen((event) { - _connectivityResult.add(ConnectivityResult.none); + _connectivityResult!.add(ConnectivityResult.none); }); } - return _connectivityResult.stream; + return _connectivityResult!.stream; } } diff --git a/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart b/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart index 99bac2ab8d30..800be2ef238f 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/network_information_api_connectivity_plugin.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'dart:html' as html show window, NetworkInformation; -import 'dart:js'; -import 'dart:js_util'; +import 'dart:js' show allowInterop; +import 'dart:js_util' show setProperty; import 'package:connectivity_platform_interface/connectivity_platform_interface.dart'; import 'package:connectivity_for_web/connectivity_for_web.dart'; @@ -18,7 +18,7 @@ class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin { /// The constructor of the plugin. NetworkInformationApiConnectivityPlugin() - : this.withConnection(html.window.navigator.connection); + : this.withConnection(html.window.navigator.connection!); /// Creates the plugin, with an override of the NetworkInformation object. @visibleForTesting @@ -32,8 +32,8 @@ class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin { return networkInformationToConnectivityResult(_networkInformation); } - StreamController _connectivityResultStreamController; - Stream _connectivityResultStream; + StreamController? _connectivityResultStreamController; + late Stream _connectivityResultStream; /// Returns a Stream of ConnectivityResults changes. @override @@ -41,8 +41,10 @@ class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin { if (_connectivityResultStreamController == null) { _connectivityResultStreamController = StreamController(); + + // Directly write the 'onchange' function on the networkInformation object. setProperty(_networkInformation, 'onchange', allowInterop((_) { - _connectivityResultStreamController + _connectivityResultStreamController! .add(networkInformationToConnectivityResult(_networkInformation)); })); // TODO: Implement the above with _networkInformation.onChange: @@ -54,7 +56,7 @@ class NetworkInformationApiConnectivityPlugin extends ConnectivityPlugin { // onChange Stream upon hot restart. // https://github.com/dart-lang/sdk/issues/42679 _connectivityResultStream = - _connectivityResultStreamController.stream.asBroadcastStream(); + _connectivityResultStreamController!.stream.asBroadcastStream(); } return _connectivityResultStream; } diff --git a/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart b/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart index efefd8d52440..e7eb8969231a 100644 --- a/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart +++ b/packages/connectivity/connectivity_for_web/lib/src/utils/connectivity_result.dart @@ -3,7 +3,7 @@ import 'package:connectivity_platform_interface/connectivity_platform_interface. /// Converts an incoming NetworkInformation object into the correct ConnectivityResult. ConnectivityResult networkInformationToConnectivityResult( - html.NetworkInformation info, + html.NetworkInformation? info, ) { if (info == null) { return ConnectivityResult.none; @@ -12,10 +12,10 @@ ConnectivityResult networkInformationToConnectivityResult( return ConnectivityResult.none; } if (info.effectiveType != null) { - return _effectiveTypeToConnectivityResult(info.effectiveType); + return _effectiveTypeToConnectivityResult(info.effectiveType!); } if (info.type != null) { - return _typeToConnectivityResult(info.type); + return _typeToConnectivityResult(info.type!); } return ConnectivityResult.none; } diff --git a/packages/connectivity/connectivity_for_web/pubspec.yaml b/packages/connectivity/connectivity_for_web/pubspec.yaml index 3622b15709b6..5c673e83b44a 100644 --- a/packages/connectivity/connectivity_for_web/pubspec.yaml +++ b/packages/connectivity/connectivity_for_web/pubspec.yaml @@ -1,7 +1,7 @@ name: connectivity_for_web description: An implementation for the web platform of the Flutter `connectivity` plugin. This uses the NetworkInformation Web API, with a fallback to Navigator.onLine. -version: 0.3.1+4 repository: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_for_web +version: 0.4.0 flutter: plugin: @@ -11,21 +11,16 @@ flutter: fileName: connectivity_for_web.dart dependencies: - connectivity_platform_interface: ^1.0.3 + connectivity_platform_interface: ^2.0.0 flutter_web_plugins: sdk: flutter flutter: sdk: flutter dev_dependencies: - flutter_driver: - sdk: flutter flutter_test: sdk: flutter - integration_test: - path: ../../integration_test - mockito: ^4.1.1 environment: - sdk: ">=2.6.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4" + sdk: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/packages/connectivity/connectivity_for_web/test/.gitignore b/packages/connectivity/connectivity_for_web/test/.gitignore deleted file mode 100644 index d7dee828a6b9..000000000000 --- a/packages/connectivity/connectivity_for_web/test/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -.DS_Store -.dart_tool/ - -.packages -.pub/ - -build/ -lib/generated_plugin_registrant.dart diff --git a/packages/connectivity/connectivity_for_web/test/README.md b/packages/connectivity/connectivity_for_web/test/README.md new file mode 100644 index 000000000000..7c5b4ad682ba --- /dev/null +++ b/packages/connectivity/connectivity_for_web/test/README.md @@ -0,0 +1,5 @@ +## test + +This package uses integration tests for testing. + +See `example/README.md` for more info. diff --git a/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart b/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart deleted file mode 100644 index 7b82b512065b..000000000000 --- a/packages/connectivity/connectivity_for_web/test/lib/src/connectivity_mocks.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dart:html'; - -import 'package:mockito/mockito.dart'; - -/// A Mock implementation of the NetworkInformation API that allows -/// for external modification of its values. -class MockNetworkInformation extends Mock implements NetworkInformation { - /// The callback that will fire after the network information values change. - Function onchange; - - /// Changes the desired values, and triggers the change event listener. - void mockChangeValue({ - String type, - String effectiveType, - num downlink, - num rtt, - }) async { - when(this.type).thenAnswer((_) => type); - when(this.effectiveType).thenAnswer((_) => effectiveType); - when(this.downlink).thenAnswer((_) => downlink); - when(this.rtt).thenAnswer((_) => rtt); - - onchange(Event('change')); - } -} diff --git a/packages/connectivity/connectivity_for_web/test/pubspec.yaml b/packages/connectivity/connectivity_for_web/test/pubspec.yaml deleted file mode 100644 index 512b7df8c26e..000000000000 --- a/packages/connectivity/connectivity_for_web/test/pubspec.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: connectivity_web_example -description: Example web app for the connectivity plugin -homepage: https://github.com/flutter/plugins/tree/master/packages/connectivity/connectivity_web - -dependencies: - connectivity_for_web: - path: ../ - js: ^0.6.1+1 - flutter_web_plugins: - sdk: flutter - flutter: - sdk: flutter - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_driver: - sdk: flutter - integration_test: - path: ../../../integration_test - mockito: ^4.1.1 - -environment: - sdk: ">=2.6.0 <3.0.0" - flutter: ">=1.12.13+hotfix.4" diff --git a/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart b/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart new file mode 100644 index 000000000000..334f52186d9d --- /dev/null +++ b/packages/connectivity/connectivity_for_web/test/tests_exist_elsewhere_test.dart @@ -0,0 +1,10 @@ +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('Tell the user where to find the real tests', () { + print('---'); + print('This package uses integration_test for its tests.'); + print('See `example/README.md` for more info.'); + print('---'); + }); +}