Commit 1ef0eadb authored by Angjie Li's avatar Angjie Li Committed by Jonah Williams

Flutter Web Driver Support (#45951)

* Support Flutter Driver test for Flutter Web application.

* Support Flutter Driver test for Flutter Web application.

* Fix documentation issues.

* Support Flutter Driver test for Flutter Web application.

* Fix documentation.

* Remove unused file from dartdoc check.

* Sync to date.

* Revert change to dartdoc.

* Address comments.

* Apply suggestions from code review
Co-Authored-By: 's avatarJonah Williams <jonahwilliams@google.com>

* Update copyrights.

* Update allowed list for browsers.

* Verify command line arguments for Drive command is correctly parsed.

* Make waitUntilFirstFrameRasterized throw unimplementedError for Flutter Web Driver.

* Add comment for why sync WebDriver is used.

* Update documentations.

* Add more unit tests and update documentation.

* Configure test.dart so that web_extension_test will be executed with --platform=chrome.

* Revert unnecessary changes.

* Add new file path for Windows to blacklist.

* Reconstruct the structure of flutter_driver/test/src folder to remove filtering logic in dev/bots/test.dart/

* Fix path to web_extension_test.dart.

* Add instructions for how to use WebFlutterDriver.

* Update getLayerTree to use sendCommand instead of _sendCommand.

* Update pubspec files.
parent f546aa7d
......@@ -19,7 +19,7 @@ dependencies:
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
front_end: 0.1.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -74,4 +74,4 @@ flutter:
assets:
- icon/
# PUBSPEC CHECKSUM: ebc8
# PUBSPEC CHECKSUM: deca
......@@ -17,6 +17,8 @@ dependencies:
# flutter update-packages --force-upgrade
flutter_gallery_assets: 0.1.9+2
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -25,17 +27,20 @@ dependencies:
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
intl: 0.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
json_rpc_2: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
path: 1.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pub_semver: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_span: 1.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vector_math: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dev_dependencies:
flutter_test:
......@@ -43,10 +48,8 @@ dev_dependencies:
test: 1.9.4
analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
front_end: 0.1.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
glob: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -59,7 +62,6 @@ dev_dependencies:
js: 0.6.1+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
kernel: 0.3.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
logging: 0.11.3+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
mime: 0.9.6+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
multi_server_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_interop: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -91,4 +93,4 @@ flutter:
- packages/flutter_gallery_assets/people/square/ali.png
- packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png
# PUBSPEC CHECKSUM: 4cef
# PUBSPEC CHECKSUM: 3f37
......@@ -17,6 +17,8 @@ dependencies:
# flutter update-packages --force-upgrade
flutter_gallery_assets: 0.1.9+2
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -25,17 +27,20 @@ dependencies:
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
intl: 0.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
json_rpc_2: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
path: 1.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pub_semver: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_span: 1.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vector_math: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dev_dependencies:
flutter_test:
......@@ -43,10 +48,8 @@ dev_dependencies:
test: 1.9.4
analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
front_end: 0.1.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
glob: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -59,7 +62,6 @@ dev_dependencies:
js: 0.6.1+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
kernel: 0.3.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
logging: 0.11.3+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
mime: 0.9.6+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
multi_server_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_interop: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -92,4 +94,4 @@ flutter:
- packages/flutter_gallery_assets/food/cherry_pie.png
- assets/999x1000.png
# PUBSPEC CHECKSUM: 4cef
# PUBSPEC CHECKSUM: 3f37
......@@ -23,7 +23,7 @@ dependencies:
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dart_style: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -79,4 +79,4 @@ dependencies:
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: e51f
# PUBSPEC CHECKSUM: e521
......@@ -24,7 +24,7 @@ dependencies:
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -70,4 +70,4 @@ dev_dependencies:
mockito: 4.1.1
test_api: 0.2.11
# PUBSPEC CHECKSUM: 2235
# PUBSPEC CHECKSUM: a937
......@@ -439,7 +439,7 @@ Future<void> _runFrameworkTests() async {
await _runFlutterTest(path.join(flutterRoot, 'examples', 'hello_world'), tableData: bigqueryApi?.tabledata);
await _runFlutterTest(path.join(flutterRoot, 'examples', 'layers'), tableData: bigqueryApi?.tabledata);
await _runFlutterTest(path.join(flutterRoot, 'examples', 'stocks'), tableData: bigqueryApi?.tabledata);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver'), tableData: bigqueryApi?.tabledata);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver'), tableData: bigqueryApi?.tabledata, tests: <String>[path.join('test', 'src', 'real_tests')]);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_goldens'), tableData: bigqueryApi?.tabledata);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations'), tableData: bigqueryApi?.tabledata);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test'), tableData: bigqueryApi?.tabledata);
......@@ -534,6 +534,10 @@ Future<void> _runWebTests() async {
path.join(flutterRoot, 'packages', 'flutter_web_plugins'),
<String>['test'],
);
await _runFlutterWebTest(
path.join(flutterRoot, 'packages', 'flutter_driver'),
<String>[path.join('test', 'src', 'web_tests', 'web_extension_test.dart')],
);
};
await selectSubshard(subshards);
......
......@@ -43,7 +43,7 @@ dev_dependencies:
analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
front_end: 0.1.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
glob: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -77,4 +77,4 @@ dev_dependencies:
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
# PUBSPEC CHECKSUM: 9e46
# PUBSPEC CHECKSUM: 9648
......@@ -20,12 +20,12 @@ dependencies:
flutter:
sdk: flutter
# This plugin is using Android Embedding 1
battery: 0.3.1+4
battery: 0.3.1+6
# TODO(egarciad): Add a plugin that uses Android Embedding 2
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: 0.1.2
cupertino_icons: 0.1.3
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -100,4 +100,4 @@ flutter:
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
# PUBSPEC CHECKSUM: fad6
# PUBSPEC CHECKSUM: 9bd9
......@@ -9,13 +9,14 @@ dependencies:
test: 1.9.4
analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -54,6 +55,7 @@ dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -63,9 +65,10 @@ dependencies:
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: f2a9
# PUBSPEC CHECKSUM: cd51
......@@ -22,7 +22,7 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: 0.1.2
cupertino_icons: 0.1.3
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -49,7 +49,7 @@ dev_dependencies:
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -90,6 +90,7 @@ dev_dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -97,6 +98,7 @@ dev_dependencies:
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
xml: 3.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -138,4 +140,4 @@ flutter:
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
# PUBSPEC CHECKSUM: 8095
# PUBSPEC CHECKSUM: c0dd
......@@ -22,7 +22,7 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: 0.1.2
cupertino_icons: 0.1.3
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -97,4 +97,4 @@ flutter:
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
# PUBSPEC CHECKSUM: 712e
# PUBSPEC CHECKSUM: 6e2f
......@@ -22,7 +22,7 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: 0.1.2
cupertino_icons: 0.1.3
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -49,7 +49,7 @@ dev_dependencies:
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -90,6 +90,7 @@ dev_dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -97,6 +98,7 @@ dev_dependencies:
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
xml: 3.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -138,4 +140,4 @@ flutter:
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
# PUBSPEC CHECKSUM: 8095
# PUBSPEC CHECKSUM: c0dd
......@@ -7,7 +7,7 @@ dependencies:
sdk: flutter
flutter_driver:
sdk: flutter
path_provider: 1.4.5
path_provider: 1.5.1
collection: 1.14.11
assets_for_android_views:
git:
......@@ -15,6 +15,8 @@ dependencies:
ref: c47f1308188dca65b3899228cac37f252ea8b411
path: dev/integration_tests/assets_for_android_views
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -22,6 +24,7 @@ dependencies:
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
intl: 0.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
json_rpc_2: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
path: 1.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
platform: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -29,11 +32,13 @@ dependencies:
source_span: 1.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vector_math: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dev_dependencies:
flutter_test:
......@@ -41,10 +46,8 @@ dev_dependencies:
test: 1.9.4
analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
front_end: 0.1.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
glob: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -57,7 +60,6 @@ dev_dependencies:
js: 0.6.1+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
kernel: 0.3.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
logging: 0.11.3+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
mime: 0.9.6+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
multi_server_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_interop: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -86,4 +88,4 @@ dev_dependencies:
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: 4173
# PUBSPEC CHECKSUM: 95b7
......@@ -13,13 +13,14 @@ dependencies:
test: 1.9.4
analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -58,6 +59,7 @@ dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -67,9 +69,10 @@ dependencies:
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: f2a9
# PUBSPEC CHECKSUM: cd51
......@@ -11,6 +11,8 @@ dependencies:
flutter_driver:
sdk: flutter
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -19,25 +21,27 @@ dependencies:
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
intl: 0.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
json_rpc_2: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
path: 1.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pub_semver: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_span: 1.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vector_math: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dev_dependencies:
test: 1.9.4
analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
front_end: 0.1.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
glob: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -49,7 +53,6 @@ dev_dependencies:
js: 0.6.1+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
kernel: 0.3.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
logging: 0.11.3+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
mime: 0.9.6+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
multi_server_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_interop: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -79,4 +82,4 @@ builders:
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: f2a9
# PUBSPEC CHECKSUM: cd51
......@@ -13,13 +13,14 @@ dependencies:
test: 1.9.4
analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -58,6 +59,7 @@ dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -67,9 +69,10 @@ dependencies:
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: f2a9
# PUBSPEC CHECKSUM: cd51
......@@ -13,13 +13,14 @@ dependencies:
test: 1.9.4
analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -58,6 +59,7 @@ dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -67,9 +69,10 @@ dependencies:
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: f2a9
# PUBSPEC CHECKSUM: cd51
......@@ -9,9 +9,11 @@ dependencies:
sdk: flutter
flutter_driver:
sdk: flutter
cupertino_icons: 0.1.2
device_info: 0.4.1+2
cupertino_icons: 0.1.3
device_info: 0.4.1+4
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -20,25 +22,27 @@ dependencies:
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
intl: 0.16.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
json_rpc_2: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
path: 1.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pub_semver: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_span: 1.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vector_math: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dev_dependencies:
test: 1.9.4
analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
front_end: 0.1.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
glob: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -50,7 +54,6 @@ dev_dependencies:
js: 0.6.1+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
kernel: 0.3.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
logging: 0.11.3+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
mime: 0.9.6+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
multi_server_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_interop: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -78,4 +81,4 @@ flutter:
assets:
- assets/
# PUBSPEC CHECKSUM: e877
# PUBSPEC CHECKSUM: 8022
......@@ -14,7 +14,7 @@ dependencies:
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
front_end: 0.1.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -63,4 +63,4 @@ dependencies:
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: a6c7
# PUBSPEC CHECKSUM: fcc9
......@@ -22,7 +22,7 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: 0.1.2
cupertino_icons: 0.1.3
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -105,4 +105,4 @@ flutter:
androidPackage: com.example.iosadd2appflutter
iosBundleIdentifier: com.example.iosAdd2appFlutter
# PUBSPEC CHECKSUM: 712e
# PUBSPEC CHECKSUM: 6e2f
......@@ -13,13 +13,14 @@ dependencies:
test: 1.9.4
analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -58,6 +59,7 @@ dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -67,9 +69,10 @@ dependencies:
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: f2a9
# PUBSPEC CHECKSUM: cd51
......@@ -17,7 +17,7 @@ dev_dependencies:
flutter_test:
sdk: flutter
e2e: 0.2.1+1
e2e: 0.2.2+3
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -40,4 +40,4 @@ dev_dependencies:
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
xml: 3.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
# PUBSPEC CHECKSUM: b92d
# PUBSPEC CHECKSUM: b430
......@@ -21,7 +21,7 @@ dependencies:
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -61,6 +61,7 @@ dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -69,6 +70,7 @@ dependencies:
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
xml: 3.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -82,4 +84,4 @@ dev_dependencies:
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: 1cf0
# PUBSPEC CHECKSUM: d238
......@@ -47,7 +47,7 @@ dev_dependencies:
test: 1.9.4
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http: 0.12.0+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http_multi_server: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http_parser: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -101,4 +101,4 @@ executables:
vm_service_client: 0.2.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.0.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
# PUBSPEC CHECKSUM: a7d1
# PUBSPEC CHECKSUM: fdd3
......@@ -35,7 +35,7 @@ dev_dependencies:
analyzer: 0.38.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
front_end: 0.1.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
glob: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -69,4 +69,4 @@ dev_dependencies:
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
# PUBSPEC CHECKSUM: 3590
# PUBSPEC CHECKSUM: 1892
......@@ -29,7 +29,7 @@ dev_dependencies:
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -69,6 +69,7 @@ dev_dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -76,10 +77,11 @@ dev_dependencies:
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
xml: 3.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: 1cf0
# PUBSPEC CHECKSUM: d238
......@@ -8,13 +8,13 @@ dependencies:
flutter:
sdk: flutter
collection: 1.14.11
device_info: 0.4.1+2
device_info: 0.4.1+4
intl: 0.16.0
connectivity: 0.4.5+6
connectivity: 0.4.6+1
string_scanner: 1.0.5
url_launcher: 5.2.7
cupertino_icons: 0.1.2
video_player: 0.10.3+3
cupertino_icons: 0.1.3
video_player: 0.10.4+2
scoped_model: 1.0.1
shrine_images: 1.1.2
......@@ -25,11 +25,13 @@ dependencies:
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
path: 1.6.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
plugin_platform_interface: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_span: 1.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
url_launcher_platform_interface: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
url_launcher_platform_interface: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vector_math: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
video_player_platform_interface: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dev_dependencies:
flutter_test:
......@@ -46,7 +48,7 @@ dev_dependencies:
async: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -85,12 +87,14 @@ dev_dependencies:
source_maps: 0.10.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
xml: 3.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -265,4 +269,4 @@ flutter:
- asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf
- asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf
# PUBSPEC CHECKSUM: ab21
# PUBSPEC CHECKSUM: fd51
// Copyright 2014 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_driver/driver_extension.dart';
import 'package:flutter_gallery/gallery/app.dart' show GalleryApp;
import 'package:flutter/material.dart';
void main() {
enableFlutterDriverExtension();
runApp(const GalleryApp(testMode: true));
}
// Copyright 2014 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 'dart:async';
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() {
group('scrolling performance test', () {
FlutterDriver driver;
setUpAll(() async {
driver = await FlutterDriver.connect(browser: true);
});
tearDownAll(() async {
if (driver != null)
driver.close();
});
test('measure', () async {
final Timeline timeline = await driver.traceAction(() async {
await driver.tap(find.text('Material'));
final SerializableFinder demoList = find.byValueKey('GalleryDemoList');
// TODO(eseidel): These are very artificial scrolls, we should use better
// https://github.com/flutter/flutter/issues/3316
// Scroll down
for (int i = 0; i < 5; i++) {
await driver.scroll(demoList, 0.0, -300.0, const Duration(milliseconds: 300));
await Future<void>.delayed(const Duration(milliseconds: 500));
}
// Scroll up
for (int i = 0; i < 5; i++) {
await driver.scroll(demoList, 0.0, 300.0, const Duration(milliseconds: 300));
await Future<void>.delayed(const Duration(milliseconds: 500));
}
});
TimelineSummary.summarize(timeline)
..writeTimelineToFile('home_scroll_perf', pretty: true);
});
});
}
......@@ -12,7 +12,7 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: 0.1.2
cupertino_icons: 0.1.3
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -60,4 +60,4 @@ flutter:
assets:
- images/coast.jpg
# PUBSPEC CHECKSUM: 712e
# PUBSPEC CHECKSUM: 6e2f
......@@ -27,7 +27,7 @@ dev_dependencies:
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -68,6 +68,7 @@ dev_dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -75,10 +76,11 @@ dev_dependencies:
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
xml: 3.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: 1cf0
# PUBSPEC CHECKSUM: d238
......@@ -27,7 +27,7 @@ dev_dependencies:
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -68,6 +68,7 @@ dev_dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -75,10 +76,11 @@ dev_dependencies:
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
xml: 3.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: 1cf0
# PUBSPEC CHECKSUM: d238
......@@ -54,7 +54,7 @@ dev_dependencies:
archive: 2.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.13.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 5.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http_multi_server: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
image: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -76,14 +76,16 @@ dev_dependencies:
source_maps: 0.10.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
xml: 3.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: e110
# PUBSPEC CHECKSUM: 3d57
......@@ -3,23 +3,15 @@
// found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:file/file.dart' as f;
import 'package:fuchsia_remote_debug_protocol/fuchsia_remote_debug_protocol.dart' as fuchsia;
import 'package:json_rpc_2/error_code.dart' as error_code;
import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
import 'package:meta/meta.dart';
import 'package:path/path.dart' as p;
import 'package:vm_service_client/vm_service_client.dart';
import 'package:web_socket_channel/io.dart';
import '../common/diagnostics_tree.dart';
import '../common/error.dart';
import '../common/find.dart';
import '../common/frame_sync.dart';
import '../common/fuchsia_compat.dart';
import '../common/geometry.dart';
import '../common/gesture.dart';
import '../common/health.dart';
......@@ -30,8 +22,12 @@ import '../common/request_data.dart';
import '../common/semantics.dart';
import '../common/text.dart';
import '../common/wait.dart';
import 'common.dart';
import 'timeline.dart';
import 'vmservice_driver.dart';
import 'web_driver.dart';
export 'vmservice_driver.dart';
export 'web_driver.dart';
/// Timeline stream identifier.
enum TimelineStream {
......@@ -63,52 +59,11 @@ enum TimelineStream {
vm,
}
const List<TimelineStream> _defaultStreams = <TimelineStream>[TimelineStream.all];
/// How long to wait before showing a message saying that
/// things seem to be taking a long time.
@visibleForTesting
const Duration kUnusuallyLongTimeout = Duration(seconds: 5);
/// The amount of time we wait prior to making the next attempt to connect to
/// the VM service.
const Duration _kPauseBetweenReconnectAttempts = Duration(seconds: 1);
// See https://github.com/dart-lang/sdk/blob/master/runtime/vm/timeline.cc#L32
String _timelineStreamsToString(List<TimelineStream> streams) {
final String contents = streams.map<String>((TimelineStream stream) {
switch (stream) {
case TimelineStream.all: return 'all';
case TimelineStream.api: return 'API';
case TimelineStream.compiler: return 'Compiler';
case TimelineStream.dart: return 'Dart';
case TimelineStream.debugger: return 'Debugger';
case TimelineStream.embedder: return 'Embedder';
case TimelineStream.gc: return 'GC';
case TimelineStream.isolate: return 'Isolate';
case TimelineStream.vm: return 'VM';
default:
throw 'Unknown timeline stream $stream';
}
}).join(', ');
return '[$contents]';
}
void _log(String message) {
driverLog('FlutterDriver', message);
}
Future<T> _warnIfSlow<T>({
@required Future<T> future,
@required Duration timeout,
@required String message,
}) {
assert(future != null);
assert(timeout != null);
assert(message != null);
return future..timeout(timeout, onTimeout: () { _log(message); return null; });
}
/// A convenient accessor to frequently used finders.
///
/// Examples:
......@@ -125,43 +80,27 @@ const CommonFinders find = CommonFinders._();
typedef EvaluatorFunction = dynamic Function();
/// Drives a Flutter Application running in another process.
class FlutterDriver {
/// Creates a driver that uses a connection provided by the given
/// [serviceClient], [_peer] and [appIsolate].
abstract class FlutterDriver {
/// Default constructor.
@visibleForTesting
FlutterDriver.connectedTo(
this.serviceClient,
this._peer,
this.appIsolate, {
bool printCommunication = false,
bool logCommunicationToFile = true,
}) : _printCommunication = printCommunication,
_logCommunicationToFile = logCommunicationToFile,
_driverId = _nextDriverId++;
static const String _flutterExtensionMethodName = 'ext.flutter.driver';
static const String _setVMTimelineFlagsMethodName = 'setVMTimelineFlags';
static const String _getVMTimelineMethodName = 'getVMTimeline';
static const String _clearVMTimelineMethodName = 'clearVMTimeline';
static const String _collectAllGarbageMethodName = '_collectAllGarbage';
static int _nextDriverId = 0;
// The additional blank line in the beginning is for _log.warning.
static const String _kDebugWarning = '''
┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓
┇ ⚠ THIS BENCHMARK IS BEING RUN IN DEBUG MODE ⚠ ┇
┡╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┦
│ │
│ Numbers obtained from a benchmark while asserts are │
│ enabled will not accurately reflect the performance │
│ that will be experienced by end users using release ╎
│ builds. Benchmarks should be run using this command ┆
│ line: flutter drive --profile test_perf.dart ┊
│ ┊
└─────────────────────────────────────────────────╌┄┈ 🐢
''';
FlutterDriver();
/// Creates a driver that uses a connection provided by either the combination
/// of [webConnection] and [browser], or the combination of [serviceClient],
/// [peer] and [appIsolate]
@visibleForTesting
factory FlutterDriver.connectedTo({
FlutterWebConnection webConnection,
Browser browser,
VMServiceClient serviceClient,
rpc.Peer peer,
VMIsolate appIsolate,
}) {
if (webConnection != null && browser != null) {
return WebFlutterDriver.connectedTo(webConnection, browser);
}
return VMServiceFlutterDriver.connectedTo(serviceClient, peer, appIsolate);
}
/// Connects to a Flutter application.
///
......@@ -188,6 +127,10 @@ class FlutterDriver {
/// `isolateNumber` is set, as this is already enough information to connect
/// to an isolate.
///
/// `browser` specifies which FlutterDriver implementation to use. If not
/// speicifed or set to false, [VMServiceFlutterDriver] implementation
/// will be used. Otherwise, [WebFlutterDriver] implementation will be used.
///
/// The return value is a future. This method never times out, though it may
/// fail (completing with an error). A timeout can be applied by the caller
/// using [Future.timeout] if necessary.
......@@ -197,308 +140,64 @@ class FlutterDriver {
bool logCommunicationToFile = true,
int isolateNumber,
Pattern fuchsiaModuleTarget,
bool browser = false,
Duration timeout,
}) async {
// If running on a Fuchsia device, connect to the first isolate whose name
// matches FUCHSIA_MODULE_TARGET.
//
// If the user has already supplied an isolate number/URL to the Dart VM
// service, then this won't be run as it is unnecessary.
if (Platform.isFuchsia && isolateNumber == null) {
// On Fuchsia stderr/stdout appear to have issues working correctly,
// so we work around the issue by using print directly.
// TODO(awdavies): Fix Dart or Fuchsia to not need this workaround.
driverLog = (String source, String message) {
print('$source: $message');
};
fuchsiaModuleTarget ??= Platform.environment['FUCHSIA_MODULE_TARGET'];
if (fuchsiaModuleTarget == null) {
throw DriverError(
'No Fuchsia module target has been specified.\n'
'Please make sure to specify the FUCHSIA_MODULE_TARGET '
'environment variable.'
);
}
final fuchsia.FuchsiaRemoteConnection fuchsiaConnection =
await FuchsiaCompat.connect();
final List<fuchsia.IsolateRef> refs =
await fuchsiaConnection.getMainIsolatesByPattern(fuchsiaModuleTarget);
final fuchsia.IsolateRef ref = refs.first;
isolateNumber = ref.number;
dartVmServiceUrl = ref.dartVm.uri.toString();
await fuchsiaConnection.stop();
FuchsiaCompat.cleanup();
}
dartVmServiceUrl ??= Platform.environment['VM_SERVICE_URL'];
if (dartVmServiceUrl == null) {
throw DriverError(
'Could not determine URL to connect to application.\n'
'Either the VM_SERVICE_URL environment variable should be set, or an explicit '
'URL should be provided to the FlutterDriver.connect() method.'
);
}
// Connect to Dart VM services
_log('Connecting to Flutter application at $dartVmServiceUrl');
final VMServiceClientConnection connection =
await vmServiceConnectFunction(dartVmServiceUrl);
final VMServiceClient client = connection.client;
final VM vm = await client.getVM();
final VMIsolateRef isolateRef = isolateNumber ==
null ? vm.isolates.first :
vm.isolates.firstWhere(
(VMIsolateRef isolate) => isolate.number == isolateNumber);
_log('Isolate found with number: ${isolateRef.number}');
VMIsolate isolate = await isolateRef.loadRunnable();
// TODO(yjbanov): vm_service_client does not support "None" pause event yet.
// It is currently reported as null, but we cannot rely on it because
// eventually the event will be reported as a non-null object. For now,
// list all the events we know about. Later we'll check for "None" event
// explicitly.
//
// See: https://github.com/dart-lang/vm_service_client/issues/4
if (isolate.pauseEvent is! VMPauseStartEvent &&
isolate.pauseEvent is! VMPauseExitEvent &&
isolate.pauseEvent is! VMPauseBreakpointEvent &&
isolate.pauseEvent is! VMPauseExceptionEvent &&
isolate.pauseEvent is! VMPauseInterruptedEvent &&
isolate.pauseEvent is! VMResumeEvent) {
isolate = await isolateRef.loadRunnable();
if (browser) {
return WebFlutterDriver.connectWeb(hostUrl: dartVmServiceUrl, timeout: timeout);
}
final FlutterDriver driver = FlutterDriver.connectedTo(
client, connection.peer, isolate,
return VMServiceFlutterDriver.connect(
dartVmServiceUrl: dartVmServiceUrl,
printCommunication: printCommunication,
logCommunicationToFile: logCommunicationToFile,
isolateNumber: isolateNumber,
fuchsiaModuleTarget: fuchsiaModuleTarget,
);
driver._dartVmReconnectUrl = dartVmServiceUrl;
// Attempts to resume the isolate, but does not crash if it fails because
// the isolate is already resumed. There could be a race with other tools,
// such as a debugger, any of which could have resumed the isolate.
Future<dynamic> resumeLeniently() {
_log('Attempting to resume isolate...');
return isolate.resume().catchError((dynamic e) {
const int vmMustBePausedCode = 101;
if (e is rpc.RpcException && e.code == vmMustBePausedCode) {
// No biggie; something else must have resumed the isolate
_log(
'Attempted to resume an already resumed isolate. This may happen '
'when we lose a race with another tool (usually a debugger) that '
'is connected to the same isolate.'
);
} else {
// Failed to resume due to another reason. Fail hard.
throw e;
}
});
}
/// Waits for a signal from the VM service that the extension is registered.
/// Returns [_flutterExtensionMethodName]
Future<String> waitForServiceExtension() {
return isolate.onExtensionAdded.firstWhere((String extension) {
return extension == _flutterExtensionMethodName;
});
}
/// Tells the Dart VM Service to notify us about "Isolate" events.
///
/// This is a workaround for an issue in package:vm_service_client, which
/// subscribes to the "Isolate" stream lazily upon subscription, which
/// results in lost events.
///
/// Details: https://github.com/dart-lang/vm_service_client/issues/17
Future<void> enableIsolateStreams() async {
await connection.peer.sendRequest('streamListen', <String, String>{
'streamId': 'Isolate',
});
}
// Attempt to resume isolate if it was paused
if (isolate.pauseEvent is VMPauseStartEvent) {
_log('Isolate is paused at start.');
// If the isolate is paused at the start, e.g. via the --start-paused
// option, then the VM service extension is not registered yet. Wait for
// it to be registered.
await enableIsolateStreams();
final Future<String> whenServiceExtensionReady = waitForServiceExtension();
final Future<dynamic> whenResumed = resumeLeniently();
await whenResumed;
_log('Waiting for service extension...');
// We will never receive the extension event if the user does not
// register it. If that happens, show a message but continue waiting.
await _warnIfSlow<String>(
future: whenServiceExtensionReady,
timeout: kUnusuallyLongTimeout,
message: 'Flutter Driver extension is taking a long time to become available. '
'Ensure your test app (often "lib/main.dart") imports '
'"package:flutter_driver/driver_extension.dart" and '
'calls enableFlutterDriverExtension() as the first call in main().',
);
} else if (isolate.pauseEvent is VMPauseExitEvent ||
isolate.pauseEvent is VMPauseBreakpointEvent ||
isolate.pauseEvent is VMPauseExceptionEvent ||
isolate.pauseEvent is VMPauseInterruptedEvent) {
// If the isolate is paused for any other reason, assume the extension is
// already there.
_log('Isolate is paused mid-flight.');
await resumeLeniently();
} else if (isolate.pauseEvent is VMResumeEvent) {
_log('Isolate is not paused. Assuming application is ready.');
} else {
_log(
'Unknown pause event type ${isolate.pauseEvent.runtimeType}. '
'Assuming application is ready.'
);
}
// Invoked checkHealth and try to fix delays in the registration of Service
// extensions
Future<Health> checkHealth() async {
try {
// At this point the service extension must be installed. Verify it.
return await driver.checkHealth();
} on rpc.RpcException catch (e) {
if (e.code != error_code.METHOD_NOT_FOUND) {
rethrow;
}
_log('Check Health failed, try to wait for the service extensions to be registered.');
await enableIsolateStreams();
await waitForServiceExtension();
return driver.checkHealth();
}
}
final Health health = await checkHealth();
if (health.status != HealthStatus.ok) {
await client.close();
throw DriverError('Flutter application health check failed.');
}
_log('Connected to Flutter application.');
return driver;
}
/// The unique ID of this driver instance.
final int _driverId;
/// Client connected to the Dart VM running the Flutter application
/// Sends [command] to the Flutter Driver extensions.
/// This must be implemented by subclass.
///
/// You can use [VMServiceClient] to check VM version, flags and get
/// notified when a new isolate has been instantiated. That could be
/// useful if your application spawns multiple isolates that you
/// would like to instrument.
final VMServiceClient serviceClient;
/// JSON-RPC client useful for sending raw JSON requests.
rpc.Peer _peer;
String _dartVmReconnectUrl;
Future<void> _restorePeerConnectionIfNeeded() async {
if (!_peer.isClosed || _dartVmReconnectUrl == null) {
return;
}
_log('Peer connection is closed! Trying to restore the connection...');
final String webSocketUrl = _getWebSocketUrl(_dartVmReconnectUrl);
final WebSocket ws = await WebSocket.connect(webSocketUrl);
ws.done.whenComplete(() => _checkCloseCode(ws));
_peer = rpc.Peer(
IOWebSocketChannel(ws).cast(),
onUnhandledError: _unhandledJsonRpcError,
)..listen();
}
/// The main isolate hosting the Flutter application.
/// See also:
///
/// If you used the [registerExtension] API to instrument your application,
/// you can use this [VMIsolate] to call these extension methods via
/// [invokeExtension].
final VMIsolate appIsolate;
/// Whether to print communication between host and app to `stdout`.
final bool _printCommunication;
/// Whether to log communication between host and app to `flutter_driver_commands.log`.
final bool _logCommunicationToFile;
Future<Map<String, dynamic>> _sendCommand(Command command) async {
Map<String, dynamic> response;
try {
final Map<String, String> serialized = command.serialize();
_logCommunication('>>> $serialized');
final Future<Map<String, dynamic>> future = appIsolate.invokeExtension(
_flutterExtensionMethodName,
serialized,
).then<Map<String, dynamic>>((Object value) => value as Map<String, dynamic>);
response = await _warnIfSlow<Map<String, dynamic>>(
future: future,
timeout: command.timeout ?? kUnusuallyLongTimeout,
message: '${command.kind} message is taking a long time to complete...',
);
_logCommunication('<<< $response');
} catch (error, stackTrace) {
throw DriverError(
'Failed to fulfill ${command.runtimeType} due to remote error',
error,
stackTrace,
);
}
if (response['isError'] as bool)
throw DriverError('Error in Flutter application: ${response['response']}');
return response['response'] as Map<String, dynamic>;
}
void _logCommunication(String message) {
if (_printCommunication)
_log(message);
if (_logCommunicationToFile) {
final f.File file = fs.file(p.join(testOutputsDirectory, 'flutter_driver_commands_$_driverId.log'));
file.createSync(recursive: true); // no-op if file exists
file.writeAsStringSync('${DateTime.now()} $message\n', mode: f.FileMode.append, flush: true);
}
}
/// * [VMServiceFlutterDriver], which uses vmservice to implement.
/// * [WebFlutterDriver], which uses webdriver to implement.
Future<Map<String, dynamic>> sendCommand(Command command);
/// Checks the status of the Flutter Driver extension.
Future<Health> checkHealth({ Duration timeout }) async {
return Health.fromJson(await _sendCommand(GetHealth(timeout: timeout)));
return Health.fromJson(await sendCommand(GetHealth(timeout: timeout)));
}
/// Returns a dump of the render tree.
Future<RenderTree> getRenderTree({ Duration timeout }) async {
return RenderTree.fromJson(await _sendCommand(GetRenderTree(timeout: timeout)));
return RenderTree.fromJson(await sendCommand(GetRenderTree(timeout: timeout)));
}
/// Returns a dump of the layer tree.
Future<LayerTree> getLayerTree({ Duration timeout }) async {
return LayerTree.fromJson(await _sendCommand(GetLayerTree(timeout: timeout)));
return LayerTree.fromJson(await sendCommand(GetLayerTree(timeout: timeout)));
}
/// Taps at the center of the widget located by [finder].
Future<void> tap(SerializableFinder finder, { Duration timeout }) async {
await _sendCommand(Tap(finder, timeout: timeout));
await sendCommand(Tap(finder, timeout: timeout));
}
/// Waits until [finder] locates the target.
Future<void> waitFor(SerializableFinder finder, { Duration timeout }) async {
await _sendCommand(WaitFor(finder, timeout: timeout));
await sendCommand(WaitFor(finder, timeout: timeout));
}
/// Waits until [finder] can no longer locate the target.
Future<void> waitForAbsent(SerializableFinder finder, { Duration timeout }) async {
await _sendCommand(WaitForAbsent(finder, timeout: timeout));
await sendCommand(WaitForAbsent(finder, timeout: timeout));
}
/// Waits until the given [waitCondition] is satisfied.
Future<void> waitForCondition(SerializableWaitCondition waitCondition, {Duration timeout}) async {
await _sendCommand(WaitForCondition(waitCondition, timeout: timeout));
await sendCommand(WaitForCondition(waitCondition, timeout: timeout));
}
/// Waits until there are no more transient callbacks in the queue.
......@@ -506,20 +205,22 @@ class FlutterDriver {
/// Use this method when you need to wait for the moment when the application
/// becomes "stable", for example, prior to taking a [screenshot].
Future<void> waitUntilNoTransientCallbacks({ Duration timeout }) async {
await _sendCommand(WaitForCondition(const NoTransientCallbacks(), timeout: timeout));
await sendCommand(WaitForCondition(const NoTransientCallbacks(), timeout: timeout));
}
/// Waits until the next [Window.onReportTimings] is called.
///
/// Use this method to wait for the first frame to be rasterized during the
/// app launch.
///
/// Throws [UnimplementedError] on [WebFlutterDriver] instances.
Future<void> waitUntilFirstFrameRasterized() async {
await _sendCommand(const WaitForCondition(FirstFrameRasterized()));
await sendCommand(const WaitForCondition(FirstFrameRasterized()));
}
Future<DriverOffset> _getOffset(SerializableFinder finder, OffsetType type, { Duration timeout }) async {
final GetOffset command = GetOffset(finder, type, timeout: timeout);
final GetOffsetResult result = GetOffsetResult.fromJson(await _sendCommand(command));
final GetOffsetResult result = GetOffsetResult.fromJson(await sendCommand(command));
return DriverOffset(result.dx, result.dy);
}
......@@ -590,7 +291,7 @@ class FlutterDriver {
bool includeProperties = true,
Duration timeout,
}) async {
return _sendCommand(GetDiagnosticsTree(
return sendCommand(GetDiagnosticsTree(
finder,
DiagnosticsType.renderObject,
subtreeDepth: subtreeDepth,
......@@ -623,7 +324,7 @@ class FlutterDriver {
bool includeProperties = true,
Duration timeout,
}) async {
return _sendCommand(GetDiagnosticsTree(
return sendCommand(GetDiagnosticsTree(
finder,
DiagnosticsType.widget,
subtreeDepth: subtreeDepth,
......@@ -646,7 +347,7 @@ class FlutterDriver {
/// The move events are generated at a given [frequency] in Hz (or events per
/// second). It defaults to 60Hz.
Future<void> scroll(SerializableFinder finder, double dx, double dy, Duration duration, { int frequency = 60, Duration timeout }) async {
await _sendCommand(Scroll(finder, dx, dy, duration, frequency, timeout: timeout));
await sendCommand(Scroll(finder, dx, dy, duration, frequency, timeout: timeout));
}
/// Scrolls the Scrollable ancestor of the widget located by [finder]
......@@ -657,7 +358,7 @@ class FlutterDriver {
/// then this method may fail because [finder] doesn't actually exist.
/// The [scrollUntilVisible] method can be used in this case.
Future<void> scrollIntoView(SerializableFinder finder, { double alignment = 0.0, Duration timeout }) async {
await _sendCommand(ScrollIntoView(finder, alignment: alignment, timeout: timeout));
await sendCommand(ScrollIntoView(finder, alignment: alignment, timeout: timeout));
}
/// Repeatedly [scroll] the widget located by [scrollable] by [dxScroll] and
......@@ -714,7 +415,7 @@ class FlutterDriver {
/// Returns the text in the `Text` widget located by [finder].
Future<String> getText(SerializableFinder finder, { Duration timeout }) async {
return GetTextResult.fromJson(await _sendCommand(GetText(finder, timeout: timeout))).text;
return GetTextResult.fromJson(await sendCommand(GetText(finder, timeout: timeout))).text;
}
/// Enters `text` into the currently focused text input, such as the
......@@ -750,7 +451,7 @@ class FlutterDriver {
/// });
/// ```
Future<void> enterText(String text, { Duration timeout }) async {
await _sendCommand(EnterText(text, timeout: timeout));
await sendCommand(EnterText(text, timeout: timeout));
}
/// Configures text entry emulation.
......@@ -768,7 +469,7 @@ class FlutterDriver {
/// channel will be mocked out.
Future<void> setTextEntryEmulation({ @required bool enabled, Duration timeout }) async {
assert(enabled != null);
await _sendCommand(SetTextEntryEmulation(enabled, timeout: timeout));
await sendCommand(SetTextEntryEmulation(enabled, timeout: timeout));
}
/// Sends a string and returns a string.
......@@ -778,7 +479,7 @@ class FlutterDriver {
/// callback in [enableFlutterDriverExtension] that can successfully handle
/// these requests.
Future<String> requestData(String message, { Duration timeout }) async {
return RequestDataResult.fromJson(await _sendCommand(RequestData(message, timeout: timeout))).message;
return RequestDataResult.fromJson(await sendCommand(RequestData(message, timeout: timeout))).message;
}
/// Turns semantics on or off in the Flutter app under test.
......@@ -786,7 +487,7 @@ class FlutterDriver {
/// Returns true when the call actually changed the state from on to off or
/// vice versa.
Future<bool> setSemantics(bool enabled, { Duration timeout }) async {
final SetSemanticsResult result = SetSemanticsResult.fromJson(await _sendCommand(SetSemantics(enabled, timeout: timeout)));
final SetSemanticsResult result = SetSemanticsResult.fromJson(await sendCommand(SetSemantics(enabled, timeout: timeout)));
return result.changedState;
}
......@@ -799,7 +500,7 @@ class FlutterDriver {
/// Semantics must be enabled to use this method, either using a platform
/// specific shell command or [setSemantics].
Future<int> getSemanticsId(SerializableFinder finder, { Duration timeout }) async {
final Map<String, dynamic> jsonResponse = await _sendCommand(GetSemanticsId(finder, timeout: timeout));
final Map<String, dynamic> jsonResponse = await sendCommand(GetSemanticsId(finder, timeout: timeout));
final GetSemanticsIdResult result = GetSemanticsIdResult.fromJson(jsonResponse);
return result.id;
}
......@@ -807,58 +508,54 @@ class FlutterDriver {
/// Take a screenshot.
///
/// The image will be returned as a PNG.
Future<List<int>> screenshot() async {
// HACK: this artificial delay here is to deal with a race between the
// driver script and the GPU thread. The issue is that driver API
// synchronizes with the framework based on transient callbacks, which
// are out of sync with the GPU thread. Here's the timeline of events
// in ASCII art:
//
// -------------------------------------------------------------------
// Without this delay:
// -------------------------------------------------------------------
// UI : <-- build -->
// GPU : <-- rasterize -->
// Gap : | random |
// Driver: <-- screenshot -->
//
// In the diagram above, the gap is the time between the last driver
// action taken, such as a `tap()`, and the subsequent call to
// `screenshot()`. The gap is random because it is determined by the
// unpredictable network communication between the driver process and
// the application. If this gap is too short, which it typically will
// be, the screenshot is taken before the GPU thread is done
// rasterizing the frame, so the screenshot of the previous frame is
// taken, which is wrong.
//
// -------------------------------------------------------------------
// With this delay, if we're lucky:
// -------------------------------------------------------------------
// UI : <-- build -->
// GPU : <-- rasterize -->
// Gap : | 2 seconds or more |
// Driver: <-- screenshot -->
//
// The two-second gap should be long enough for the GPU thread to
// finish rasterizing the frame, but not longer than necessary to keep
// driver tests as fast a possible.
//
// -------------------------------------------------------------------
// With this delay, if we're not lucky:
// -------------------------------------------------------------------
// UI : <-- build -->
// GPU : <-- rasterize randomly slow today -->
// Gap : | 2 seconds or more |
// Driver: <-- screenshot -->
//
// In practice, sometimes the device gets really busy for a while and
// even two seconds isn't enough, which means that this is still racy
// and a source of flakes.
await Future<void>.delayed(const Duration(seconds: 2));
final Map<String, dynamic> result = await _peer.sendRequest('_flutter.screenshot') as Map<String, dynamic>;
return base64.decode(result['screenshot'] as String);
}
///
/// HACK: There will be a 2-second artificial delay before screenshotting,
/// the delay here is to deal with a race between the driver script and
/// the GPU thread. The issue is that driver API synchronizes with the
/// framework based on transient callbacks, which are out of sync with
/// the GPU thread. Here's the timeline of events in ASCII art:
///
/// -------------------------------------------------------------------
/// Without this delay:
/// -------------------------------------------------------------------
/// UI : <-- build -->
/// GPU : <-- rasterize -->
/// Gap : | random |
/// Driver: <-- screenshot -->
///
/// In the diagram above, the gap is the time between the last driver
/// action taken, such as a `tap()`, and the subsequent call to
/// `screenshot()`. The gap is random because it is determined by the
/// unpredictable network communication between the driver process and
/// the application. If this gap is too short, which it typically will
/// be, the screenshot is taken before the GPU thread is done
/// rasterizing the frame, so the screenshot of the previous frame is
/// taken, which is wrong.
///
/// -------------------------------------------------------------------
/// With this delay, if we're lucky:
/// -------------------------------------------------------------------
/// UI : <-- build -->
/// GPU : <-- rasterize -->
/// Gap : | 2 seconds or more |
/// Driver: <-- screenshot -->
///
/// The two-second gap should be long enough for the GPU thread to
/// finish rasterizing the frame, but not longer than necessary to keep
/// driver tests as fast a possible.
///
/// -------------------------------------------------------------------
/// With this delay, if we're not lucky:
/// -------------------------------------------------------------------
/// UI : <-- build -->
/// GPU : <-- rasterize randomly slow today -->
/// Gap : | 2 seconds or more |
/// Driver: <-- screenshot -->
///
/// In practice, sometimes the device gets really busy for a while and
/// even two seconds isn't enough, which means that this is still racy
/// and a source of flakes.
Future<List<int>> screenshot();
/// Returns the Flags set in the Dart VM as JSON.
///
......@@ -879,76 +576,32 @@ class FlutterDriver {
/// ]
///
/// [getFlagList]: https://github.com/dart-lang/sdk/blob/master/runtime/vm/service/service.md#getflaglist
Future<List<Map<String, dynamic>>> getVmFlags() async {
await _restorePeerConnectionIfNeeded();
final Map<String, dynamic> result = await _peer.sendRequest('getFlagList') as Map<String, dynamic>;
return result != null
? (result['flags'] as List<dynamic>).cast<Map<String,dynamic>>()
: const <Map<String, dynamic>>[];
}
///
/// Throws [UnimplementedError] on [WebFlutterDriver] instances.
Future<List<Map<String, dynamic>>> getVmFlags();
/// Starts recording performance traces.
///
/// The `timeout` argument causes a warning to be displayed to the user if the
/// operation exceeds the specified timeout; it does not actually cancel the
/// operation.
///
/// For [WebFlutterDriver], this is only supported for Chrome.
Future<void> startTracing({
List<TimelineStream> streams = _defaultStreams,
List<TimelineStream> streams = const <TimelineStream>[TimelineStream.all],
Duration timeout = kUnusuallyLongTimeout,
}) async {
assert(streams != null && streams.isNotEmpty);
assert(timeout != null);
try {
await _warnIfSlow<void>(
future: _peer.sendRequest(_setVMTimelineFlagsMethodName, <String, String>{
'recordedStreams': _timelineStreamsToString(streams),
}),
timeout: timeout,
message: 'VM is taking an unusually long time to respond to being told to start tracing...',
);
} catch (error, stackTrace) {
throw DriverError(
'Failed to start tracing due to remote error',
error,
stackTrace,
);
}
}
});
/// Stops recording performance traces and downloads the timeline.
///
/// The `timeout` argument causes a warning to be displayed to the user if the
/// operation exceeds the specified timeout; it does not actually cancel the
/// operation.
///
/// For [WebFlutterDriver], this is only supported for Chrome.
Future<Timeline> stopTracingAndDownloadTimeline({
Duration timeout = kUnusuallyLongTimeout,
}) async {
assert(timeout != null);
try {
await _warnIfSlow<void>(
future: _peer.sendRequest(_setVMTimelineFlagsMethodName, <String, String>{'recordedStreams': '[]'}),
timeout: timeout,
message: 'VM is taking an unusually long time to respond to being told to stop tracing...',
);
return Timeline.fromJson(await _peer.sendRequest(_getVMTimelineMethodName) as Map<String, dynamic>);
} catch (error, stackTrace) {
throw DriverError(
'Failed to stop tracing due to remote error',
error,
stackTrace,
);
}
}
Future<bool> _isPrecompiledMode() async {
final List<Map<String, dynamic>> flags = await getVmFlags();
for(Map<String, dynamic> flag in flags) {
if (flag['name'] == 'precompiled_mode') {
return flag['valueAsString'] == 'true';
}
}
return false;
}
});
/// Runs [action] and outputs a performance trace for it.
///
......@@ -967,46 +620,24 @@ class FlutterDriver {
///
/// If this is run in debug mode, a warning message will be printed to suggest
/// running the benchmark in profile mode instead.
///
/// For [WebFlutterDriver], this is only supported for Chrome.
Future<Timeline> traceAction(
Future<dynamic> action(), {
List<TimelineStream> streams = _defaultStreams,
List<TimelineStream> streams = const <TimelineStream>[TimelineStream.all],
bool retainPriorEvents = false,
}) async {
if (!retainPriorEvents) {
await clearTimeline();
}
await startTracing(streams: streams);
await action();
if (!(await _isPrecompiledMode())) {
_log(_kDebugWarning);
}
return stopTracingAndDownloadTimeline();
}
});
/// Clears all timeline events recorded up until now.
///
/// The `timeout` argument causes a warning to be displayed to the user if the
/// operation exceeds the specified timeout; it does not actually cancel the
/// operation.
///
/// For [WebFlutterDriver], this is only supported for Chrome.
Future<void> clearTimeline({
Duration timeout = kUnusuallyLongTimeout,
}) async {
assert(timeout != null);
try {
await _warnIfSlow<void>(
future: _peer.sendRequest(_clearVMTimelineMethodName, <String, String>{}),
timeout: timeout,
message: 'VM is taking an unusually long time to respond to being told to clear its timeline buffer...',
);
} catch (error, stackTrace) {
throw DriverError(
'Failed to clear event timeline due to remote error',
error,
stackTrace,
);
}
}
});
/// [action] will be executed with the frame sync mechanism disabled.
///
......@@ -1025,155 +656,25 @@ class FlutterDriver {
/// ensure that no action is performed while the app is undergoing a
/// transition to avoid flakiness.
Future<T> runUnsynchronized<T>(Future<T> action(), { Duration timeout }) async {
await _sendCommand(SetFrameSync(false, timeout: timeout));
await sendCommand(SetFrameSync(false, timeout: timeout));
T result;
try {
result = await action();
} finally {
await _sendCommand(SetFrameSync(true, timeout: timeout));
await sendCommand(SetFrameSync(true, timeout: timeout));
}
return result;
}
/// Force a garbage collection run in the VM.
Future<void> forceGC() async {
try {
await _peer
.sendRequest(_collectAllGarbageMethodName, <String, String>{
'isolateId': 'isolates/${appIsolate.numberAsString}',
});
} catch (error, stackTrace) {
throw DriverError(
'Failed to force a GC due to remote error',
error,
stackTrace,
);
}
}
///
/// Throws [UnimplementedError] on [WebFlutterDriver] instances.
Future<void> forceGC();
/// Closes the underlying connection to the VM service.
///
/// Returns a [Future] that fires once the connection has been closed.
Future<void> close() async {
// Don't leak vm_service_client-specific objects, if any
await serviceClient.close();
await _peer.close();
}
}
/// Encapsulates connection information to an instance of a Flutter application.
@visibleForTesting
class VMServiceClientConnection {
/// Creates an instance of this class given a [client] and a [peer].
VMServiceClientConnection(this.client, this.peer);
/// Use this for structured access to the VM service's public APIs.
final VMServiceClient client;
/// Use this to make arbitrary raw JSON-RPC calls.
///
/// This object allows reaching into private VM service APIs. Use with
/// caution.
final rpc.Peer peer;
}
/// A function that connects to a Dart VM service given the [url].
typedef VMServiceConnectFunction = Future<VMServiceClientConnection> Function(String url);
/// The connection function used by [FlutterDriver.connect].
///
/// Overwrite this function if you require a custom method for connecting to
/// the VM service.
VMServiceConnectFunction vmServiceConnectFunction = _waitAndConnect;
/// Restores [vmServiceConnectFunction] to its default value.
void restoreVmServiceConnectFunction() {
vmServiceConnectFunction = _waitAndConnect;
}
/// The JSON RPC 2 spec says that a notification from a client must not respond
/// to the client. It's possible the client sent a notification as a "ping", but
/// the service isn't set up yet to respond.
///
/// For example, if the client sends a notification message to the server for
/// 'streamNotify', but the server has not finished loading, it will throw an
/// exception. Since the message is a notification, the server follows the
/// specification and does not send a response back, but is left with an
/// unhandled exception. That exception is safe for us to ignore - the client
/// is signaling that it will try again later if it doesn't get what it wants
/// here by sending a notification.
// This may be ignoring too many exceptions. It would be best to rewrite
// the client code to not use notifications so that it gets error replies back
// and can decide what to do from there.
// TODO(dnfield): https://github.com/flutter/flutter/issues/31813
bool _ignoreRpcError(dynamic error) {
if (error is rpc.RpcException) {
final rpc.RpcException exception = error;
return exception.data == null || exception.data['id'] == null;
} else if (error is String && error.startsWith('JSON-RPC error -32601')) {
return true;
}
return false;
}
void _unhandledJsonRpcError(dynamic error, dynamic stack) {
if (_ignoreRpcError(error)) {
return;
}
_log('Unhandled RPC error:\n$error\n$stack');
// TODO(dnfield): https://github.com/flutter/flutter/issues/31813
// assert(false);
}
String _getWebSocketUrl(String url) {
Uri uri = Uri.parse(url);
final List<String> pathSegments = <String>[
// If there's an authentication code (default), we need to add it to our path.
if (uri.pathSegments.isNotEmpty) uri.pathSegments.first,
'ws',
];
if (uri.scheme == 'http')
uri = uri.replace(scheme: 'ws', pathSegments: pathSegments);
return uri.toString();
}
void _checkCloseCode(WebSocket ws) {
if (ws.closeCode != 1000 && ws.closeCode != null) {
_log('$ws is closed with an unexpected code ${ws.closeCode}');
}
}
/// Waits for a real Dart VM service to become available, then connects using
/// the [VMServiceClient].
Future<VMServiceClientConnection> _waitAndConnect(String url) async {
final String webSocketUrl = _getWebSocketUrl(url);
int attempts = 0;
while (true) {
WebSocket ws1;
WebSocket ws2;
try {
ws1 = await WebSocket.connect(webSocketUrl);
ws2 = await WebSocket.connect(webSocketUrl);
ws1.done.whenComplete(() => _checkCloseCode(ws1));
ws2.done.whenComplete(() => _checkCloseCode(ws2));
return VMServiceClientConnection(
VMServiceClient(IOWebSocketChannel(ws1).cast()),
rpc.Peer(
IOWebSocketChannel(ws2).cast(),
onUnhandledError: _unhandledJsonRpcError,
)..listen(),
);
} catch (e) {
await ws1?.close();
await ws2?.close();
if (attempts > 5)
_log('It is taking an unusually long time to connect to the VM...');
attempts += 1;
await Future<void>.delayed(_kPauseBetweenReconnectAttempts);
}
}
Future<void> close();
}
/// Provides convenient accessors to frequently used finders.
......
// Copyright 2014 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 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:file/file.dart' as f;
import 'package:fuchsia_remote_debug_protocol/fuchsia_remote_debug_protocol.dart' as fuchsia;
import 'package:json_rpc_2/error_code.dart' as error_code;
import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
import 'package:meta/meta.dart';
import 'package:path/path.dart' as p;
import 'package:vm_service_client/vm_service_client.dart';
import 'package:web_socket_channel/io.dart';
import '../../flutter_driver.dart';
import '../common/error.dart';
import '../common/frame_sync.dart';
import '../common/fuchsia_compat.dart';
import '../common/health.dart';
import '../common/message.dart';
import 'common.dart';
import 'driver.dart';
import 'timeline.dart';
/// An implementation of the Flutter Driver over the vmservice protocol.
class VMServiceFlutterDriver extends FlutterDriver {
/// Creates a driver that uses a connection provided by the given
/// [serviceClient], [_peer] and [appIsolate].
VMServiceFlutterDriver.connectedTo(
this._serviceClient,
this._peer,
this._appIsolate, {
bool printCommunication = false,
bool logCommunicationToFile = true,
}) : _printCommunication = printCommunication,
_logCommunicationToFile = logCommunicationToFile,
_driverId = _nextDriverId++;
/// Connects to a Flutter application.
///
/// See [FlutterDriver.connect] for more documentation.
static Future<FlutterDriver> connect({
String dartVmServiceUrl,
bool printCommunication = false,
bool logCommunicationToFile = true,
int isolateNumber,
Pattern fuchsiaModuleTarget,
}) async {
// If running on a Fuchsia device, connect to the first isolate whose name
// matches FUCHSIA_MODULE_TARGET.
//
// If the user has already supplied an isolate number/URL to the Dart VM
// service, then this won't be run as it is unnecessary.
if (Platform.isFuchsia && isolateNumber == null) {
// TODO(awdavies): Use something other than print. On fuchsia
// `stderr`/`stdout` appear to have issues working correctly.
driverLog = (String source, String message) {
print('$source: $message');
};
fuchsiaModuleTarget ??= Platform.environment['FUCHSIA_MODULE_TARGET'];
if (fuchsiaModuleTarget == null) {
throw DriverError(
'No Fuchsia module target has been specified.\n'
'Please make sure to specify the FUCHSIA_MODULE_TARGET '
'environment variable.'
);
}
final fuchsia.FuchsiaRemoteConnection fuchsiaConnection =
await FuchsiaCompat.connect();
final List<fuchsia.IsolateRef> refs =
await fuchsiaConnection.getMainIsolatesByPattern(fuchsiaModuleTarget);
final fuchsia.IsolateRef ref = refs.first;
isolateNumber = ref.number;
dartVmServiceUrl = ref.dartVm.uri.toString();
await fuchsiaConnection.stop();
FuchsiaCompat.cleanup();
}
dartVmServiceUrl ??= Platform.environment['VM_SERVICE_URL'];
if (dartVmServiceUrl == null) {
throw DriverError(
'Could not determine URL to connect to application.\n'
'Either the VM_SERVICE_URL environment variable should be set, or an explicit '
'URL should be provided to the FlutterDriver.connect() method.'
);
}
// Connect to Dart VM services
_log('Connecting to Flutter application at $dartVmServiceUrl');
final VMServiceClientConnection connection =
await vmServiceConnectFunction(dartVmServiceUrl);
final VMServiceClient client = connection.client;
final VM vm = await client.getVM();
final VMIsolateRef isolateRef = isolateNumber ==
null ? vm.isolates.first :
vm.isolates.firstWhere(
(VMIsolateRef isolate) => isolate.number == isolateNumber);
_log('Isolate found with number: ${isolateRef.number}');
VMIsolate isolate = await isolateRef.loadRunnable();
// TODO(yjbanov): vm_service_client does not support "None" pause event yet.
// It is currently reported as null, but we cannot rely on it because
// eventually the event will be reported as a non-null object. For now,
// list all the events we know about. Later we'll check for "None" event
// explicitly.
//
// See: https://github.com/dart-lang/vm_service_client/issues/4
if (isolate.pauseEvent is! VMPauseStartEvent &&
isolate.pauseEvent is! VMPauseExitEvent &&
isolate.pauseEvent is! VMPauseBreakpointEvent &&
isolate.pauseEvent is! VMPauseExceptionEvent &&
isolate.pauseEvent is! VMPauseInterruptedEvent &&
isolate.pauseEvent is! VMResumeEvent) {
isolate = await isolateRef.loadRunnable();
}
final VMServiceFlutterDriver driver = VMServiceFlutterDriver.connectedTo(
client, connection.peer, isolate,
printCommunication: printCommunication,
logCommunicationToFile: logCommunicationToFile,
);
driver._dartVmReconnectUrl = dartVmServiceUrl;
// Attempts to resume the isolate, but does not crash if it fails because
// the isolate is already resumed. There could be a race with other tools,
// such as a debugger, any of which could have resumed the isolate.
Future<dynamic> resumeLeniently() {
_log('Attempting to resume isolate');
return isolate.resume().catchError((dynamic e) {
const int vmMustBePausedCode = 101;
if (e is rpc.RpcException && e.code == vmMustBePausedCode) {
// No biggie; something else must have resumed the isolate
_log(
'Attempted to resume an already resumed isolate. This may happen '
'when we lose a race with another tool (usually a debugger) that '
'is connected to the same isolate.'
);
} else {
// Failed to resume due to another reason. Fail hard.
throw e;
}
});
}
/// Waits for a signal from the VM service that the extension is registered.
/// Returns [_flutterExtensionMethodName]
Future<String> waitForServiceExtension() {
return isolate.onExtensionAdded.firstWhere((String extension) {
return extension == _flutterExtensionMethodName;
});
}
/// Tells the Dart VM Service to notify us about "Isolate" events.
///
/// This is a workaround for an issue in package:vm_service_client, which
/// subscribes to the "Isolate" stream lazily upon subscription, which
/// results in lost events.
///
/// Details: https://github.com/dart-lang/vm_service_client/issues/17
Future<void> enableIsolateStreams() async {
await connection.peer.sendRequest('streamListen', <String, String>{
'streamId': 'Isolate',
});
}
// Attempt to resume isolate if it was paused
if (isolate.pauseEvent is VMPauseStartEvent) {
_log('Isolate is paused at start.');
// If the isolate is paused at the start, e.g. via the --start-paused
// option, then the VM service extension is not registered yet. Wait for
// it to be registered.
await enableIsolateStreams();
final Future<String> whenServiceExtensionReady = waitForServiceExtension();
final Future<dynamic> whenResumed = resumeLeniently();
await whenResumed;
_log('Waiting for service extension');
// We will never receive the extension event if the user does not
// register it. If that happens, show a message but continue waiting.
await _warnIfSlow<String>(
future: whenServiceExtensionReady,
timeout: kUnusuallyLongTimeout,
message: 'Flutter Driver extension is taking a long time to become available. '
'Ensure your test app (often "lib/main.dart") imports '
'"package:flutter_driver/driver_extension.dart" and '
'calls enableFlutterDriverExtension() as the first call in main().',
);
} else if (isolate.pauseEvent is VMPauseExitEvent ||
isolate.pauseEvent is VMPauseBreakpointEvent ||
isolate.pauseEvent is VMPauseExceptionEvent ||
isolate.pauseEvent is VMPauseInterruptedEvent) {
// If the isolate is paused for any other reason, assume the extension is
// already there.
_log('Isolate is paused mid-flight.');
await resumeLeniently();
} else if (isolate.pauseEvent is VMResumeEvent) {
_log('Isolate is not paused. Assuming application is ready.');
} else {
_log(
'Unknown pause event type ${isolate.pauseEvent.runtimeType}. '
'Assuming application is ready.'
);
}
// Invoked checkHealth and try to fix delays in the registration of Service
// extensions
Future<Health> checkHealth() async {
try {
// At this point the service extension must be installed. Verify it.
return await driver.checkHealth();
} on rpc.RpcException catch (e) {
if (e.code != error_code.METHOD_NOT_FOUND) {
rethrow;
}
_log(
'Check Health failed, try to wait for the service extensions to be'
'registered.'
);
await enableIsolateStreams();
await waitForServiceExtension();
return driver.checkHealth();
}
}
final Health health = await checkHealth();
if (health.status != HealthStatus.ok) {
await client.close();
throw DriverError('Flutter application health check failed.');
}
_log('Connected to Flutter application.');
return driver;
}
static int _nextDriverId = 0;
static const String _flutterExtensionMethodName = 'ext.flutter.driver';
static const String _setVMTimelineFlagsMethodName = 'setVMTimelineFlags';
static const String _getVMTimelineMethodName = 'getVMTimeline';
static const String _clearVMTimelineMethodName = 'clearVMTimeline';
static const String _collectAllGarbageMethodName = '_collectAllGarbage';
// The additional blank line in the beginning is for _log.
static const String _kDebugWarning = '''
┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓
┇ ⚠ THIS BENCHMARK IS BEING RUN IN DEBUG MODE ⚠ ┇
┡╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┦
│ │
│ Numbers obtained from a benchmark while asserts are │
│ enabled will not accurately reflect the performance │
│ that will be experienced by end users using release ╎
│ builds. Benchmarks should be run using this command ┆
│ line: flutter drive --profile test_perf.dart ┊
│ ┊
└─────────────────────────────────────────────────╌┄┈ 🐢
''';
/// The unique ID of this driver instance.
final int _driverId;
/// Client connected to the Dart VM running the Flutter application
///
/// You can use [VMServiceClient] to check VM version, flags and get
/// notified when a new isolate has been instantiated. That could be
/// useful if your application spawns multiple isolates that you
/// would like to instrument.
final VMServiceClient _serviceClient;
/// JSON-RPC client useful for sending raw JSON requests.
rpc.Peer _peer;
String _dartVmReconnectUrl;
Future<void> _restorePeerConnectionIfNeeded() async {
if (!_peer.isClosed || _dartVmReconnectUrl == null) {
return;
}
_log(
'Peer connection is closed! Trying to restore the connection...'
);
final String webSocketUrl = _getWebSocketUrl(_dartVmReconnectUrl);
final WebSocket ws = await WebSocket.connect(webSocketUrl);
ws.done.whenComplete(() => _checkCloseCode(ws));
_peer = rpc.Peer(
IOWebSocketChannel(ws).cast(),
onUnhandledError: _unhandledJsonRpcError,
)..listen();
}
/// The main isolate hosting the Flutter application.
///
/// If you used the [registerExtension] API to instrument your application,
/// you can use this [VMIsolate] to call these extension methods via
/// [invokeExtension].
final VMIsolate _appIsolate;
/// Whether to print communication between host and app to `stdout`.
final bool _printCommunication;
/// Whether to log communication between host and app to `flutter_driver_commands.log`.
final bool _logCommunicationToFile;
@override
Future<Map<String, dynamic>> sendCommand(Command command) async {
Map<String, dynamic> response;
try {
final Map<String, String> serialized = command.serialize();
_logCommunication('>>> $serialized');
final Future<Map<String, dynamic>> future = _appIsolate.invokeExtension(
_flutterExtensionMethodName,
serialized,
).then<Map<String, dynamic>>((Object value) => value as Map<String, dynamic>);
response = await _warnIfSlow<Map<String, dynamic>>(
future: future,
timeout: command.timeout ?? kUnusuallyLongTimeout,
message: '${command.kind} message is taking a long time to complete...',
);
_logCommunication('<<< $response');
} catch (error, stackTrace) {
throw DriverError(
'Failed to fulfill ${command.runtimeType} due to remote error',
error,
stackTrace,
);
}
if (response['isError'] as bool)
throw DriverError('Error in Flutter application: ${response['response']}');
return response['response'] as Map<String, dynamic>;
}
void _logCommunication(String message) {
if (_printCommunication)
_log(message);
if (_logCommunicationToFile) {
final f.File file = fs.file(p.join(testOutputsDirectory, 'flutter_driver_commands_$_driverId.log'));
file.createSync(recursive: true); // no-op if file exists
file.writeAsStringSync('${DateTime.now()} $message\n', mode: f.FileMode.append, flush: true);
}
}
@override
Future<List<int>> screenshot() async {
await Future<void>.delayed(const Duration(seconds: 2));
final Map<String, dynamic> result = await _peer.sendRequest('_flutter.screenshot') as Map<String, dynamic>;
return base64.decode(result['screenshot'] as String);
}
@override
Future<List<Map<String, dynamic>>> getVmFlags() async {
await _restorePeerConnectionIfNeeded();
final Map<String, dynamic> result = await _peer.sendRequest('getFlagList') as Map<String, dynamic>;
return result != null
? (result['flags'] as List<dynamic>).cast<Map<String,dynamic>>()
: const <Map<String, dynamic>>[];
}
@override
Future<void> startTracing({
List<TimelineStream> streams = const <TimelineStream>[TimelineStream.all],
Duration timeout = kUnusuallyLongTimeout,
}) async {
assert(streams != null && streams.isNotEmpty);
assert(timeout != null);
try {
await _warnIfSlow<void>(
future: _peer.sendRequest(_setVMTimelineFlagsMethodName, <String, String>{
'recordedStreams': _timelineStreamsToString(streams),
}),
timeout: timeout,
message: 'VM is taking an unusually long time to respond to being told to start tracing...',
);
} catch (error, stackTrace) {
throw DriverError(
'Failed to start tracing due to remote error',
error,
stackTrace,
);
}
}
@override
Future<Timeline> stopTracingAndDownloadTimeline({
Duration timeout = kUnusuallyLongTimeout,
}) async {
assert(timeout != null);
try {
await _warnIfSlow<void>(
future: _peer.sendRequest(_setVMTimelineFlagsMethodName, <String, String>{'recordedStreams': '[]'}),
timeout: timeout,
message: 'VM is taking an unusually long time to respond to being told to stop tracing...',
);
return Timeline.fromJson(await _peer.sendRequest(_getVMTimelineMethodName) as Map<String, dynamic>);
} catch (error, stackTrace) {
throw DriverError(
'Failed to stop tracing due to remote error',
error,
stackTrace,
);
}
}
Future<bool> _isPrecompiledMode() async {
final List<Map<String, dynamic>> flags = await getVmFlags();
for(Map<String, dynamic> flag in flags) {
if (flag['name'] == 'precompiled_mode') {
return flag['valueAsString'] == 'true';
}
}
return false;
}
@override
Future<Timeline> traceAction(
Future<dynamic> action(), {
List<TimelineStream> streams = const <TimelineStream>[TimelineStream.all],
bool retainPriorEvents = false,
}) async {
if (!retainPriorEvents) {
await clearTimeline();
}
await startTracing(streams: streams);
await action();
if (!(await _isPrecompiledMode())) {
_log(_kDebugWarning);
}
return stopTracingAndDownloadTimeline();
}
@override
Future<void> clearTimeline({
Duration timeout = kUnusuallyLongTimeout,
}) async {
assert(timeout != null);
try {
await _warnIfSlow<void>(
future: _peer.sendRequest(_clearVMTimelineMethodName, <String, String>{}),
timeout: timeout,
message: 'VM is taking an unusually long time to respond to being told to clear its timeline buffer...',
);
} catch (error, stackTrace) {
throw DriverError(
'Failed to clear event timeline due to remote error',
error,
stackTrace,
);
}
}
@override
Future<T> runUnsynchronized<T>(Future<T> action(), { Duration timeout }) async {
await sendCommand(SetFrameSync(false, timeout: timeout));
T result;
try {
result = await action();
} finally {
await sendCommand(SetFrameSync(true, timeout: timeout));
}
return result;
}
@override
Future<void> forceGC() async {
try {
await _peer
.sendRequest(_collectAllGarbageMethodName, <String, String>{
'isolateId': 'isolates/${_appIsolate.numberAsString}',
});
} catch (error, stackTrace) {
throw DriverError(
'Failed to force a GC due to remote error',
error,
stackTrace,
);
}
}
@override
Future<void> close() async {
// Don't leak vm_service_client-specific objects, if any
await _serviceClient.close();
await _peer.close();
}
}
/// The connection function used by [FlutterDriver.connect].
///
/// Overwrite this function if you require a custom method for connecting to
/// the VM service.
VMServiceConnectFunction vmServiceConnectFunction = _waitAndConnect;
/// Restores [vmServiceConnectFunction] to its default value.
void restoreVmServiceConnectFunction() {
vmServiceConnectFunction = _waitAndConnect;
}
/// The JSON RPC 2 spec says that a notification from a client must not respond
/// to the client. It's possible the client sent a notification as a "ping", but
/// the service isn't set up yet to respond.
///
/// For example, if the client sends a notification message to the server for
/// 'streamNotify', but the server has not finished loading, it will throw an
/// exception. Since the message is a notification, the server follows the
/// specification and does not send a response back, but is left with an
/// unhandled exception. That exception is safe for us to ignore - the client
/// is signaling that it will try again later if it doesn't get what it wants
/// here by sending a notification.
// This may be ignoring too many exceptions. It would be best to rewrite
// the client code to not use notifications so that it gets error replies back
// and can decide what to do from there.
// TODO(dnfield): https://github.com/flutter/flutter/issues/31813
bool _ignoreRpcError(dynamic error) {
if (error is rpc.RpcException) {
final rpc.RpcException exception = error;
return exception.data == null || exception.data['id'] == null;
} else if (error is String && error.startsWith('JSON-RPC error -32601')) {
return true;
}
return false;
}
void _unhandledJsonRpcError(dynamic error, dynamic stack) {
if (_ignoreRpcError(error)) {
return;
}
_log('Unhandled RPC error:\n$error\n$stack');
// TODO(dnfield): https://github.com/flutter/flutter/issues/31813
// assert(false);
}
String _getWebSocketUrl(String url) {
Uri uri = Uri.parse(url);
final List<String> pathSegments = <String>[
// If there's an authentication code (default), we need to add it to our path.
if (uri.pathSegments.isNotEmpty) uri.pathSegments.first,
'ws',
];
if (uri.scheme == 'http')
uri = uri.replace(scheme: 'ws', pathSegments: pathSegments);
return uri.toString();
}
void _checkCloseCode(WebSocket ws) {
if (ws.closeCode != 1000 && ws.closeCode != null) {
_log('$ws is closed with an unexpected code ${ws.closeCode}');
}
}
/// Waits for a real Dart VM service to become available, then connects using
/// the [VMServiceClient].
Future<VMServiceClientConnection> _waitAndConnect(String url) async {
final String webSocketUrl = _getWebSocketUrl(url);
int attempts = 0;
while (true) {
WebSocket ws1;
WebSocket ws2;
try {
ws1 = await WebSocket.connect(webSocketUrl);
ws2 = await WebSocket.connect(webSocketUrl);
ws1.done.whenComplete(() => _checkCloseCode(ws1));
ws2.done.whenComplete(() => _checkCloseCode(ws2));
return VMServiceClientConnection(
VMServiceClient(IOWebSocketChannel(ws1).cast()),
rpc.Peer(
IOWebSocketChannel(ws2).cast(),
onUnhandledError: _unhandledJsonRpcError,
)..listen(),
);
} catch (e) {
await ws1?.close();
await ws2?.close();
if (attempts > 5)
_log('It is taking an unusually long time to connect to the VM...');
attempts += 1;
await Future<void>.delayed(_kPauseBetweenReconnectAttempts);
}
}
}
/// The amount of time we wait prior to making the next attempt to connect to
/// the VM service.
const Duration _kPauseBetweenReconnectAttempts = Duration(seconds: 1);
// See https://github.com/dart-lang/sdk/blob/master/runtime/vm/timeline.cc#L32
String _timelineStreamsToString(List<TimelineStream> streams) {
final String contents = streams.map<String>((TimelineStream stream) {
switch (stream) {
case TimelineStream.all: return 'all';
case TimelineStream.api: return 'API';
case TimelineStream.compiler: return 'Compiler';
case TimelineStream.dart: return 'Dart';
case TimelineStream.debugger: return 'Debugger';
case TimelineStream.embedder: return 'Embedder';
case TimelineStream.gc: return 'GC';
case TimelineStream.isolate: return 'Isolate';
case TimelineStream.vm: return 'VM';
default:
throw 'Unknown timeline stream $stream';
}
}).join(', ');
return '[$contents]';
}
void _log(String message) {
driverLog('VMServiceFlutterDriver', message);
}
Future<T> _warnIfSlow<T>({
@required Future<T> future,
@required Duration timeout,
@required String message,
}) {
assert(future != null);
assert(timeout != null);
assert(message != null);
return future..timeout(timeout, onTimeout: () { _log(message); return null; });
}
/// Encapsulates connection information to an instance of a Flutter application.
@visibleForTesting
class VMServiceClientConnection {
/// Creates an instance of this class given a [client] and a [peer].
VMServiceClientConnection(this.client, this.peer);
/// Use this for structured access to the VM service's public APIs.
final VMServiceClient client;
/// Use this to make arbitrary raw JSON-RPC calls.
///
/// This object allows reaching into private VM service APIs. Use with
/// caution.
final rpc.Peer peer;
}
/// A function that connects to a Dart VM service given the [url].
typedef VMServiceConnectFunction = Future<VMServiceClientConnection> Function(String url);
// Copyright 2014 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 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math' as math;
import 'package:matcher/matcher.dart';
import 'package:meta/meta.dart';
import 'package:webdriver/sync_io.dart' as sync_io;
import 'package:webdriver/support/async.dart';
import '../common/error.dart';
import '../common/message.dart';
import 'driver.dart';
import 'timeline.dart';
import 'web_driver_config.dart';
export 'web_driver_config.dart';
/// An implementation of the Flutter Driver using the WebDriver.
///
/// Example of how to test WebFlutterDriver:
/// 1. Have Selenium server (https://bit.ly/2TlkRyu) and WebDriver binary (https://chromedriver.chromium.org/downloads) downloaded and placed under the same folder
/// 2. Launch WebDriver Server: java -jar selenium-server-standalone-3.141.59.jar
/// 3. Launch Flutter Web application: flutter run -v -d chrome --target=test_driver/scroll_perf_web.dart
/// 4. Run test script: flutter drive --target=test_driver/scroll_perf.dart -v --use-existing-app=/application address/
class WebFlutterDriver extends FlutterDriver {
/// Creates a driver that uses a connection provided by the given
/// [_connection] and [_browserName].
WebFlutterDriver.connectedTo(this._connection, this._browser);
final FlutterWebConnection _connection;
final Browser _browser;
DateTime _startTime;
/// Start time for tracing
@visibleForTesting
DateTime get startTime => _startTime;
/// Creates a driver that uses a connection provided by the given
/// [hostUrl] which would fallback to environment variable VM_SERVICE_URL.
/// Driver also depends on environment variables BROWSER_NAME,
/// BROWSER_DIMENSION, HEADLESS and SELENIUM_PORT for configurations.
static Future<FlutterDriver> connectWeb(
{String hostUrl, Duration timeout}) async {
hostUrl ??= Platform.environment['VM_SERVICE_URL'];
final Browser browser = browserNameToEnum(Platform.environment['BROWSER_NAME']);
final Map<String, dynamic> settings = <String, dynamic>{
'browser': browser,
'browser-dimension': Platform.environment['BROWSER_DIMENSION'],
'headless': Platform.environment['HEADLESS']?.toLowerCase() == 'true',
'selenium-port': Platform.environment['SELENIUM_PORT'],
};
final FlutterWebConnection connection = await FlutterWebConnection.connect
(hostUrl, settings, timeout: timeout);
return WebFlutterDriver.connectedTo(connection, browser);
}
@override
Future<Map<String, dynamic>> sendCommand(Command command) async {
Map<String, dynamic> response;
final Map<String, String> serialized = command.serialize();
try {
final dynamic data = await _connection.sendCommand('window.\$flutterDriver(\'${jsonEncode(serialized)}\')', command.timeout);
response = data != null ? json.decode(data as String) as Map<String, dynamic> : <String, dynamic>{};
} catch (error, stackTrace) {
throw DriverError('Failed to respond to $command due to remote error\n : \$flutterDriver(\'${jsonEncode(serialized)}\')',
error,
stackTrace
);
}
if (response['isError'] == true)
throw DriverError('Error in Flutter application: ${response['response']}');
return response['response'] as Map<String, dynamic>;
}
@override
Future<void> close() => _connection.close();
@override
Future<void> forceGC() async {
throw UnimplementedError();
}
@override
Future<List<Map<String, Object>>> getVmFlags() async {
throw UnimplementedError();
}
@override
Future<void> waitUntilFirstFrameRasterized() async {
throw UnimplementedError();
}
@override
Future<List<int>> screenshot() async {
await Future<void>.delayed(const Duration(seconds: 2));
return _connection.screenshot();
}
@override
Future<void> startTracing({
List<TimelineStream> streams = const <TimelineStream>[TimelineStream.all],
Duration timeout = kUnusuallyLongTimeout,
}) async {
_checkBrowserSupportsTimeline();
_startTime = DateTime.now();
}
@override
Future<Timeline> stopTracingAndDownloadTimeline({Duration timeout = kUnusuallyLongTimeout}) async {
_checkBrowserSupportsTimeline();
if (_startTime == null) {
return null;
}
final List<Map<String, dynamic>> events = <Map<String, dynamic>>[];
for (sync_io.LogEntry entry in _connection.logs) {
if (_startTime.isBefore(entry.timestamp)) {
final Map<String, dynamic> data = jsonDecode(entry.message)['message'] as Map<String, dynamic>;
if (data['method'] == 'Tracing.dataCollected') {
// 'ts' data collected from Chrome is in double format, conversion needed
try {
data['params']['ts'] =
double.parse(data['params']['ts'].toString()).toInt();
} on FormatException catch (_) {
// data is corrupted, skip
continue;
}
events.add(data['params'] as Map<String, dynamic>);
}
}
}
final Map<String, dynamic> json = <String, dynamic>{
'traceEvents': events,
};
_startTime = null;
return Timeline.fromJson(json);
}
@override
Future<Timeline> traceAction(Future<dynamic> Function() action, {
List<TimelineStream> streams = const <TimelineStream>[TimelineStream.all],
bool retainPriorEvents = false,
}) async {
_checkBrowserSupportsTimeline();
if (!retainPriorEvents) {
await clearTimeline();
}
await startTracing(streams: streams);
await action();
return stopTracingAndDownloadTimeline();
}
@override
Future<void> clearTimeline({Duration timeout = kUnusuallyLongTimeout}) async {
_checkBrowserSupportsTimeline();
// Reset start time
_startTime = null;
}
/// Checks whether browser supports Timeline related operations
void _checkBrowserSupportsTimeline() {
if (_browser != Browser.chrome) {
throw UnimplementedError();
}
}
}
/// Encapsulates connection information to an instance of a Flutter Web application.
class FlutterWebConnection {
FlutterWebConnection._(this._driver);
final sync_io.WebDriver _driver;
/// Starts WebDriver with the given [capabilities] and
/// establishes the connection to Flutter Web application.
static Future<FlutterWebConnection> connect(
String url,
Map<String, dynamic> settings,
{Duration timeout}) async {
// Use sync WebDriver because async version will create a 15 seconds
// overhead when quitting.
final sync_io.WebDriver driver = createDriver(settings);
driver.get(url);
// Configure WebDriver browser by setting its location and dimension.
final List<String> dimensions = settings['browser-dimension'].split(',') as List<String>;
if (dimensions.length != 2) {
throw DriverError('Invalid browser window size.');
}
final int x = int.parse(dimensions[0]);
final int y = int.parse(dimensions[1]);
final sync_io.Window window = driver.window;
window.setLocation(const math.Point<int>(0, 0));
window.setSize(math.Rectangle<int>(0, 0, x, y));
// Wait until extension is installed.
await waitFor<void>(() => driver.execute('return typeof(window.\$flutterDriver)', <String>[]),
matcher: 'function',
timeout: timeout ?? const Duration(days: 365));
return FlutterWebConnection._(driver);
}
/// Sends command via WebDriver to Flutter web application
Future<dynamic> sendCommand(String script, Duration duration) async {
dynamic result;
try {
_driver.execute(script, <void>[]);
} catch (_) {
// In case there is an exception, do nothing
}
try {
result = await waitFor<dynamic>(() => _driver.execute('r'
'eturn \$flutterDriverResult', <String>[]),
matcher: isNotNull,
timeout: duration ?? const Duration(days: 30));
} catch (_) {
// Returns null if exception thrown.
return null;
} finally {
// Resets the result.
_driver.execute('''
\$flutterDriverResult = null
''', <void>[]);
}
return result;
}
/// Gets performance log from WebDriver.
List<sync_io.LogEntry> get logs => _driver.logs.get(sync_io.LogType.performance);
/// Takes screenshot via WebDriver.
List<int> screenshot() => _driver.captureScreenshotAsList();
/// Closes the WebDriver.
Future<void> close() async {
_driver.quit();
}
}
// Copyright 2014 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:meta/meta.dart';
import 'package:webdriver/sync_io.dart' as sync_io;
import '../common/error.dart';
/// A list of supported browsers
enum Browser {
/// Chrome: https://www.google.com/chrome/
chrome,
/// Edge: https://www.microsoft.com/en-us/windows/microsoft-edge
edge,
/// Firefox: https://www.mozilla.org/en-US/firefox/
firefox,
/// Safari in iOS: https://www.apple.com/safari/
iosSafari,
/// Safari in macOS: https://www.apple.com/safari/
safari,
}
/// Converts [browserName] string to [Browser]
Browser browserNameToEnum(String browserName){
switch (browserName) {
case 'chrome': return Browser.chrome;
case 'edge': return Browser.edge;
case 'firefox': return Browser.firefox;
case 'ios-safari': return Browser.iosSafari;
case 'safari': return Browser.safari;
}
throw DriverError('Browser $browserName not supported');
}
/// Creates a WebDriver instance with the given [settings].
sync_io.WebDriver createDriver(Map<String, dynamic> settings) {
return _createDriver(
settings['selenium-port'] as String,
settings['browser'] as Browser,
settings['headless'] as bool
);
}
sync_io.WebDriver _createDriver(String seleniumPort, Browser browser, bool headless) {
return sync_io.createDriver(
uri: Uri.parse('http://localhost:$seleniumPort/wd/hub/'),
desired: getDesiredCapabilities(browser, headless),
spec: browser != Browser.iosSafari ? sync_io.WebDriverSpec.JsonWire : sync_io.WebDriverSpec.W3c
);
}
/// Returns desired capabilities for given [browser] and [headless].
@visibleForTesting
Map<String, dynamic> getDesiredCapabilities(Browser browser, bool headless) {
switch (browser) {
case Browser.chrome:
return <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'chrome',
'goog:loggingPrefs': <String, String>{ sync_io.LogType.performance: 'ALL'},
'chromeOptions': <String, dynamic>{
'args': <String>[
'--bwsi',
'--disable-background-timer-throttling',
'--disable-default-apps',
'--disable-extensions',
'--disable-popup-blocking',
'--disable-translate',
'--no-default-browser-check',
'--no-sandbox',
'--no-first-run',
if (headless) '--headless'
],
'perfLoggingPrefs': <String, String>{
'traceCategories':
'devtools.timeline,'
'v8,blink.console,benchmark,blink,'
'blink.user_timing'
}
}
};
break;
case Browser.firefox:
return <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'firefox',
'moz:firefoxOptions' : <String, dynamic>{
'args': <String>[
if (headless) '-headless'
],
'prefs': <String, dynamic>{
'dom.file.createInChild': true,
'dom.timeout.background_throttling_max_budget': -1,
'media.autoplay.default': 0,
'media.gmp-manager.url': '',
'media.gmp-provider.enabled': false,
'network.captive-portal-service.enabled': false,
'security.insecure_field_warning.contextual.enabled': false,
'test.currentTimeOffsetSeconds': 11491200
},
'log': <String, String>{'level': 'trace'}
}
};
break;
case Browser.edge:
return <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'edge',
};
break;
case Browser.safari:
return <String, dynamic>{
'browserName': 'safari',
'safari.options': <String, dynamic>{
'skipExtensionInstallation': true,
'cleanSession': true
}
};
break;
case Browser.iosSafari:
return <String, dynamic>{
'platformName': 'ios',
'browserName': 'safari',
'safari:useSimulator': true
};
default:
throw DriverError('Browser $browser not supported.');
}
}
......@@ -4,15 +4,14 @@
import 'dart:async';
import 'package:flutter/semantics.dart';
import 'package:meta/meta.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart' show RendererBinding, SemanticsHandle;
import 'package:flutter/scheduler.dart';
import 'package:flutter/semantics.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
......@@ -31,6 +30,7 @@ import '../common/request_data.dart';
import '../common/semantics.dart';
import '../common/text.dart';
import '../common/wait.dart';
import 'io_extension.dart' if (dart.library.html) 'web_extension.dart';
import 'wait_conditions.dart';
const String _extensionMethodName = 'driver';
......@@ -56,6 +56,9 @@ class _DriverBinding extends BindingBase with ServicesBinding, SchedulerBinding,
name: _extensionMethodName,
callback: extension.call,
);
if (kIsWeb) {
registerWebServiceExtension(extension.call);
}
}
@override
......
// Copyright 2014 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.
/// The dart:io implementation of [registerWebServiceExtension].
///
/// See also:
///
/// * [web_extension.dart], which has the dart:html implementation
void registerWebServiceExtension(Future<Map<String, dynamic>> Function(Map<String, String>) call) {
throw UnsupportedError('Use registerServiceExtension instead');
}
// Copyright 2014 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 'dart:async';
import 'dart:convert';
import 'dart:html' as html;
import 'dart:js';
import 'dart:js_util' as js_util;
/// The dart:html implementation of [registerWebServiceExtension].
///
/// Registers Web Service Extension for Flutter Web application.
///
/// window.$flutterDriver will be called by Flutter Web Driver to process
/// Flutter Command.
///
/// See also:
///
/// * [io_extension.dart], which has the dart:io implemeantion
void registerWebServiceExtension(Future<Map<String, dynamic>> Function(Map<String, String>) call) {
js_util.setProperty(html.window, '\$flutterDriver', allowInterop((dynamic message) async {
// ignore: undefined_function, undefined_identifier
final Map<String, String> params = Map<String, String>.from(
jsonDecode(message as String) as Map<String, dynamic>);
final Map<String, dynamic> result = Map<String, dynamic>.from(
await call(params));
context['\$flutterDriverResult'] = json.encode(result);
}));
}
......@@ -14,6 +14,7 @@ dependencies:
path: 1.6.4
web_socket_channel: 1.1.0
vm_service_client: 0.2.6+2
webdriver: 2.1.1
flutter:
sdk: flutter
flutter_test:
......@@ -41,6 +42,7 @@ dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -51,4 +53,4 @@ dev_dependencies:
mockito: 4.1.1
quiver: 2.0.5
# PUBSPEC CHECKSUM: a765
# PUBSPEC CHECKSUM: 1daa
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'package:flutter_driver/src/common/error.dart';
import 'package:flutter_driver/src/common/health.dart';
......@@ -20,6 +21,8 @@ import 'common.dart';
/// Magical timeout value that's different from the default.
const Duration _kTestTimeout = Duration(milliseconds: 1234);
const String _kSerializedTestTimeout = '1234';
const String _kWebScriptPrefix = 'window.\$flutterDriver(\'';
const String _kWebScriptSuffix = '\')';
void main() {
final List<String> log = <String>[];
......@@ -27,7 +30,7 @@ void main() {
log.add('$source: $message');
};
group('FlutterDriver.connect', () {
group('VMServiceFlutterDriver.connect', () {
MockVMServiceClient mockClient;
MockVM mockVM;
MockIsolate mockIsolate;
......@@ -115,17 +118,17 @@ void main() {
});
});
group('FlutterDriver', () {
group('VMServiceFlutterDriver', () {
MockVMServiceClient mockClient;
MockPeer mockPeer;
MockIsolate mockIsolate;
FlutterDriver driver;
VMServiceFlutterDriver driver;
setUp(() {
mockClient = MockVMServiceClient();
mockPeer = MockPeer();
mockIsolate = MockIsolate();
driver = FlutterDriver.connectedTo(mockClient, mockPeer, mockIsolate);
driver = VMServiceFlutterDriver.connectedTo(mockClient, mockPeer, mockIsolate);
});
test('checks the health of the driver extension', () async {
......@@ -615,7 +618,7 @@ void main() {
expect(log, <String>[]);
time.elapse(kUnusuallyLongTimeout);
});
expect(log, <String>['FlutterDriver: waitFor message is taking a long time to complete...']);
expect(log, <String>['VMServiceFlutterDriver: waitFor message is taking a long time to complete...']);
});
test('local custom timeout', () async {
......@@ -630,7 +633,7 @@ void main() {
expect(log, <String>[]);
time.elapse(customTimeout);
});
expect(log, <String>['FlutterDriver: waitFor message is taking a long time to complete...']);
expect(log, <String>['VMServiceFlutterDriver: waitFor message is taking a long time to complete...']);
});
test('remote error', () async {
......@@ -650,17 +653,17 @@ void main() {
});
});
group('FlutterDriver with custom timeout', () {
group('VMServiceFlutterDriver with custom timeout', () {
MockVMServiceClient mockClient;
MockPeer mockPeer;
MockIsolate mockIsolate;
FlutterDriver driver;
VMServiceFlutterDriver driver;
setUp(() {
mockClient = MockVMServiceClient();
mockPeer = MockPeer();
mockIsolate = MockIsolate();
driver = FlutterDriver.connectedTo(mockClient, mockPeer, mockIsolate);
driver = VMServiceFlutterDriver.connectedTo(mockClient, mockPeer, mockIsolate);
});
test('GetHealth has no default timeout', () async {
......@@ -684,6 +687,377 @@ void main() {
await driver.checkHealth(timeout: _kTestTimeout);
});
});
group('WebFlutterDriver', () {
MockFlutterWebConnection mockConnection;
WebFlutterDriver driver;
setUp(() {
mockConnection = MockFlutterWebConnection();
driver = WebFlutterDriver.connectedTo(mockConnection, Browser.chrome);
});
test('closes connection', () async {
when(mockConnection.close()).thenAnswer((Invocation invocation) => Future<dynamic>.value(null));
await driver.close();
});
group('ByValueKey', () {
test('restricts value types', () async {
expect(() => find.byValueKey(null),
throwsA(isInstanceOf<DriverError>()));
});
test('finds by ValueKey', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'tap',
'timeout': _kSerializedTestTimeout,
'finderType': 'ByValueKey',
'keyValueString': 'foo',
'keyValueType': 'String',
});
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
});
await driver.tap(find.byValueKey('foo'), timeout: _kTestTimeout);
});
});
group('BySemanticsLabel', () {
test('finds by Semantic label using String', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'tap',
'timeout': _kSerializedTestTimeout,
'finderType': 'BySemanticsLabel',
'label': 'foo',
});
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
});
await driver.tap(find.bySemanticsLabel('foo'), timeout: _kTestTimeout);
});
test('finds by Semantic label using RegExp', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'tap',
'timeout': _kSerializedTestTimeout,
'finderType': 'BySemanticsLabel',
'label': '^foo',
'isRegExp': 'true',
});
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
});
await driver.tap(find.bySemanticsLabel(RegExp('^foo')), timeout: _kTestTimeout);
});
});
group('tap', () {
test('requires a target reference', () async {
expect(driver.tap(null), throwsA(isInstanceOf<DriverError>()));
});
test('sends the tap command', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'tap',
'timeout': _kSerializedTestTimeout,
'finderType': 'ByText',
'text': 'foo',
});
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
});
await driver.tap(find.text('foo'), timeout: _kTestTimeout);
});
});
group('getText', () {
test('requires a target reference', () async {
expect(driver.getText(null), throwsA(isInstanceOf<DriverError>()));
});
test('sends the getText command', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'get_text',
'timeout': _kSerializedTestTimeout,
'finderType': 'ByValueKey',
'keyValueString': '123',
'keyValueType': 'int',
});
return jsonEncode(await makeMockResponse(<String, String>{
'text': 'hello',
}));
});
final String result = await driver.getText(find.byValueKey(123), timeout: _kTestTimeout);
expect(result, 'hello');
});
});
group('waitFor', () {
test('requires a target reference', () async {
expect(driver.waitFor(null), throwsA(isInstanceOf<DriverError>()));
});
test('sends the waitFor command', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'waitFor',
'finderType': 'ByTooltipMessage',
'text': 'foo',
'timeout': _kSerializedTestTimeout,
});
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
});
await driver.waitFor(find.byTooltip('foo'), timeout: _kTestTimeout);
});
});
group('waitForCondition', () {
test('sends the wait for NoPendingFrameCondition command', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'waitForCondition',
'timeout': _kSerializedTestTimeout,
'conditionName': 'NoPendingFrameCondition',
});
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
});
await driver.waitForCondition(const NoPendingFrame(), timeout: _kTestTimeout);
});
test('sends the wait for NoPendingPlatformMessages command', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'waitForCondition',
'timeout': _kSerializedTestTimeout,
'conditionName': 'NoPendingPlatformMessagesCondition',
});
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
});
await driver.waitForCondition(const NoPendingPlatformMessages(), timeout: _kTestTimeout);
});
test('sends the waitForCondition of combined conditions command', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'waitForCondition',
'timeout': _kSerializedTestTimeout,
'conditionName': 'CombinedCondition',
'conditions': '[{"conditionName":"NoPendingFrameCondition"},{"conditionName":"NoTransientCallbacksCondition"}]',
});
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
});
const SerializableWaitCondition combinedCondition =
CombinedCondition(<SerializableWaitCondition>[NoPendingFrame(), NoTransientCallbacks()]);
await driver.waitForCondition(combinedCondition, timeout: _kTestTimeout);
});
});
group('waitUntilNoTransientCallbacks', () {
test('sends the waitUntilNoTransientCallbacks command', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'waitForCondition',
'timeout': _kSerializedTestTimeout,
'conditionName': 'NoTransientCallbacksCondition',
});
return jsonEncode(await makeMockResponse(<String, dynamic>{}));
});
await driver.waitUntilNoTransientCallbacks(timeout: _kTestTimeout);
});
});
group('getOffset', () {
test('requires a target reference', () async {
expect(driver.getCenter(null), throwsA(isInstanceOf<DriverError>()));
expect(driver.getTopLeft(null), throwsA(isInstanceOf<DriverError>()));
expect(driver.getTopRight(null), throwsA(isInstanceOf<DriverError>()));
expect(driver.getBottomLeft(null), throwsA(isInstanceOf<DriverError>()));
expect(driver.getBottomRight(null), throwsA(isInstanceOf<DriverError>()));
});
test('sends the getCenter command', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'get_offset',
'offsetType': 'center',
'timeout': _kSerializedTestTimeout,
'finderType': 'ByValueKey',
'keyValueString': '123',
'keyValueType': 'int',
});
return jsonEncode(await makeMockResponse(<String, double>{
'dx': 11,
'dy': 12,
}));
});
final DriverOffset result = await driver.getCenter(find.byValueKey(123), timeout: _kTestTimeout);
expect(result, const DriverOffset(11, 12));
});
test('sends the getTopLeft command', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'get_offset',
'offsetType': 'topLeft',
'timeout': _kSerializedTestTimeout,
'finderType': 'ByValueKey',
'keyValueString': '123',
'keyValueType': 'int',
});
return jsonEncode(await makeMockResponse(<String, double>{
'dx': 11,
'dy': 12,
}));
});
final DriverOffset result = await driver.getTopLeft(find.byValueKey(123), timeout: _kTestTimeout);
expect(result, const DriverOffset(11, 12));
});
test('sends the getTopRight command', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'get_offset',
'offsetType': 'topRight',
'timeout': _kSerializedTestTimeout,
'finderType': 'ByValueKey',
'keyValueString': '123',
'keyValueType': 'int',
});
return jsonEncode(await makeMockResponse(<String, double>{
'dx': 11,
'dy': 12,
}));
});
final DriverOffset result = await driver.getTopRight(find.byValueKey(123), timeout: _kTestTimeout);
expect(result, const DriverOffset(11, 12));
});
test('sends the getBottomLeft command', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'get_offset',
'offsetType': 'bottomLeft',
'timeout': _kSerializedTestTimeout,
'finderType': 'ByValueKey',
'keyValueString': '123',
'keyValueType': 'int',
});
return jsonEncode(await makeMockResponse(<String, double>{
'dx': 11,
'dy': 12,
}));
});
final DriverOffset result = await driver.getBottomLeft(find.byValueKey(123), timeout: _kTestTimeout);
expect(result, const DriverOffset(11, 12));
});
test('sends the getBottomRight command', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'get_offset',
'offsetType': 'bottomRight',
'timeout': _kSerializedTestTimeout,
'finderType': 'ByValueKey',
'keyValueString': '123',
'keyValueType': 'int',
});
return jsonEncode(await makeMockResponse(<String, double>{
'dx': 11,
'dy': 12,
}));
});
final DriverOffset result = await driver.getBottomRight(find.byValueKey(123), timeout: _kTestTimeout);
expect(result, const DriverOffset(11, 12));
});
});
test('checks the health of the driver extension', () async {
when(mockConnection.sendCommand(any, any)).thenAnswer((Invocation i) async {
final String script = _checkAndEncode(i.positionalArguments[0]);
expect(Map<String, String>.from(jsonDecode(script) as Map<String, dynamic>), <String, String>{
'command': 'get_health',
});
return jsonEncode(await makeMockResponse(<String, dynamic>{'status': 'ok'}));
});
await driver.checkHealth();
});
group('clearTimeline', () {
test('clears timeline', () async {
await driver.startTracing();
expect(driver.startTime, isNotNull);
await driver.clearTimeline();
expect(driver.startTime, isNull);
});
});
group('WebFlutterDriver Unimplemented error', () {
test('forceGC', () async {
expect(driver.forceGC(),
throwsA(isInstanceOf<UnimplementedError>()));
});
test('getVmFlags', () async {
expect(driver.getVmFlags(),
throwsA(isInstanceOf<UnimplementedError>()));
});
test('waitUntilFirstFrameRasterized', () async {
expect(driver.waitUntilFirstFrameRasterized(),
throwsA(isInstanceOf<UnimplementedError>()));
});
});
});
group('WebFlutterDriver with non-chrome browser', () {
MockFlutterWebConnection mockConnection;
WebFlutterDriver driver;
setUp(() {
mockConnection = MockFlutterWebConnection();
driver = WebFlutterDriver.connectedTo(mockConnection, Browser.edge);
});
test('tracing', () async {
expect(driver.traceAction(() async { return Future<dynamic>.value(); }),
throwsA(isInstanceOf<UnimplementedError>()));
expect(driver.startTracing(),
throwsA(isInstanceOf<UnimplementedError>()));
expect(driver.stopTracingAndDownloadTimeline(),
throwsA(isInstanceOf<UnimplementedError>()));
expect(driver.clearTimeline(),
throwsA(isInstanceOf<UnimplementedError>()));
});
});
}
/// This function will verify the format of the script
/// and return the actual script.
/// script will be in the following format:
// window.flutterDriver('[actual script]')
String _checkAndEncode(dynamic script) {
expect(script is String, isTrue);
expect(script.startsWith(_kWebScriptPrefix), isTrue);
expect(script.endsWith(_kWebScriptSuffix), isTrue);
// Strip prefix and suffix
return script.substring(_kWebScriptPrefix.length, script.length - 2) as String;
}
Future<Map<String, dynamic>> makeMockResponse(
......@@ -708,6 +1082,8 @@ class MockVMPauseBreakpointEvent extends Mock implements VMPauseBreakpointEvent
class MockVMResumeEvent extends Mock implements VMResumeEvent { }
class MockFlutterWebConnection extends Mock implements FlutterWebConnection { }
class MockPeer extends Mock implements rpc.Peer {
@override
bool get isClosed => false;
......
......@@ -4,7 +4,7 @@
import 'package:flutter_driver/src/common/find.dart';
import '../common.dart';
import '../../common.dart';
void main() {
test('Ancestor finder serialize', () {
......
// Copyright 2014 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_driver/src/extension/io_extension.dart';
import '../../common.dart';
void main() {
group('test io_extension',() {
Future<Map<String, dynamic>> Function(Map<String, String>) call;
setUp(() {
call = (Map<String, String> args) async {
return Future<Map<String, dynamic>>.value(args);
};
});
test('io_extension should throw exception', () {
expect(() => registerWebServiceExtension(call),
throwsA(isInstanceOf<UnsupportedError>()));
});
});
}
......@@ -9,7 +9,7 @@ import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_driver/src/driver/common.dart';
import 'package:path/path.dart' as path;
import '../common.dart';
import '../../common.dart';
void main() {
group('TimelineSummary', () {
......
......@@ -4,7 +4,7 @@
import 'package:flutter_driver/src/driver/timeline.dart';
import '../common.dart';
import '../../common.dart';
void main() {
group('Timeline', () {
......
......@@ -4,7 +4,7 @@
import 'package:flutter_driver/src/common/wait.dart';
import '../common.dart';
import '../../common.dart';
void main() {
group('WaitForCondition', () {
......
// Copyright 2014 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_driver/src/driver/web_driver_config.dart';
import 'package:webdriver/sync_io.dart' as sync_io;
import '../../common.dart';
void main() {
group('getDesiredCapabilities', () {
test('Chrome with headless on', () {
final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'chrome',
'goog:loggingPrefs': <String, String>{ sync_io.LogType.performance: 'ALL'},
'chromeOptions': <String, dynamic>{
'args': <String>[
'--bwsi',
'--disable-background-timer-throttling',
'--disable-default-apps',
'--disable-extensions',
'--disable-popup-blocking',
'--disable-translate',
'--no-default-browser-check',
'--no-sandbox',
'--no-first-run',
'--headless'
],
'perfLoggingPrefs': <String, String>{
'traceCategories':
'devtools.timeline,'
'v8,blink.console,benchmark,blink,'
'blink.user_timing'
}
}
};
expect(getDesiredCapabilities(Browser.chrome, true), expected);
});
test('Chrome with headless off', () {
final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'chrome',
'goog:loggingPrefs': <String, String>{ sync_io.LogType.performance: 'ALL'},
'chromeOptions': <String, dynamic>{
'args': <String>[
'--bwsi',
'--disable-background-timer-throttling',
'--disable-default-apps',
'--disable-extensions',
'--disable-popup-blocking',
'--disable-translate',
'--no-default-browser-check',
'--no-sandbox',
'--no-first-run',
],
'perfLoggingPrefs': <String, String>{
'traceCategories':
'devtools.timeline,'
'v8,blink.console,benchmark,blink,'
'blink.user_timing'
}
}
};
expect(getDesiredCapabilities(Browser.chrome, false), expected);
});
test('Firefox with headless on', () {
final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'firefox',
'moz:firefoxOptions' : <String, dynamic>{
'args': <String>['-headless'],
'prefs': <String, dynamic>{
'dom.file.createInChild': true,
'dom.timeout.background_throttling_max_budget': -1,
'media.autoplay.default': 0,
'media.gmp-manager.url': '',
'media.gmp-provider.enabled': false,
'network.captive-portal-service.enabled': false,
'security.insecure_field_warning.contextual.enabled': false,
'test.currentTimeOffsetSeconds': 11491200
},
'log': <String, String>{'level': 'trace'}
}
};
expect(getDesiredCapabilities(Browser.firefox, true), expected);
});
test('Firefox with headless off', () {
final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'firefox',
'moz:firefoxOptions' : <String, dynamic>{
'args': <String>[],
'prefs': <String, dynamic>{
'dom.file.createInChild': true,
'dom.timeout.background_throttling_max_budget': -1,
'media.autoplay.default': 0,
'media.gmp-manager.url': '',
'media.gmp-provider.enabled': false,
'network.captive-portal-service.enabled': false,
'security.insecure_field_warning.contextual.enabled': false,
'test.currentTimeOffsetSeconds': 11491200
},
'log': <String, String>{'level': 'trace'}
}
};
expect(getDesiredCapabilities(Browser.firefox, false), expected);
});
test('Edge', () {
final Map<String, dynamic> expected = <String, dynamic>{
'acceptInsecureCerts': true,
'browserName': 'edge',
};
expect(getDesiredCapabilities(Browser.edge, false), expected);
});
test('macOS Safari', () {
final Map<String, dynamic> expected = <String, dynamic>{
'browserName': 'safari',
'safari.options': <String, dynamic>{
'skipExtensionInstallation': true,
'cleanSession': true
}
};
expect(getDesiredCapabilities(Browser.safari, false), expected);
});
test('iOS Safari', () {
final Map<String, dynamic> expected = <String, dynamic>{
'platformName': 'ios',
'browserName': 'safari',
'safari:useSimulator': true
};
expect(getDesiredCapabilities(Browser.iosSafari, false), expected);
});
});
}
// Copyright 2014 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 'dart:js' as js;
import 'package:flutter_driver/src/extension/web_extension.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('test web_extension', () {
Future<Map<String, dynamic>> Function(Map<String, String>) call;
setUp(() {
call = (Map<String, String> args) async {
return Future<Map<String, dynamic>>.value(args);
};
});
test('web_extension should register a function', () {
expect(() => registerWebServiceExtension(call),
returnsNormally);
expect(js.context.hasProperty('\$flutterDriver'), true);
});
});
}
......@@ -69,6 +69,34 @@ class DriveCommand extends RunCommandBase {
..addFlag('build',
defaultsTo: true,
help: 'Build the app before running.',
)
..addOption('driver-port',
defaultsTo: '4444',
help: 'The port where Webdriver server is launched at. Defaults to 4444.',
valueHelp: '4444'
)
..addFlag('headless',
defaultsTo: true,
help: 'Whether the driver browser is going to be launched in headless mode. Defaults to true.',
)
..addOption('browser-name',
defaultsTo: 'chrome',
help: 'Name of browser where tests will be executed. \n'
'Following browsers are supported: \n'
'Chrome, Firefox, Safari (macOS and iOS) and Edge. Defaults to Chrome.',
allowed: <String>[
'chrome',
'edge',
'firefox',
'ios-safari',
'safari',
]
)
..addOption('browser-dimension',
defaultsTo: '1600,1024',
help: 'The dimension of browser when running Flutter Web test. \n'
'This will affect screenshot and all offset-related actions. \n'
'By default. it is set to 1600,1024 (1600 by 1024).',
);
}
......@@ -133,8 +161,16 @@ class DriveCommand extends RunCommandBase {
Cache.releaseLockEarly();
final Map<String, String> environment = <String, String>{
'VM_SERVICE_URL': observatoryUri,
'SELENIUM_PORT': argResults['driver-port'].toString(),
'BROWSER_NAME': argResults['browser-name'].toString(),
'BROWSER_DIMENSION': argResults['browser-dimension'].toString(),
'HEADLESS': argResults['headless'].toString(),
};
try {
await testRunner(<String>[testFile], observatoryUri);
await testRunner(<String>[testFile], environment);
} catch (error, stackTrace) {
if (error is ToolExit) {
rethrow;
......@@ -291,13 +327,13 @@ Future<LaunchResult> _startApp(DriveCommand command) async {
}
/// Runs driver tests.
typedef TestRunner = Future<void> Function(List<String> testArgs, String observatoryUri);
typedef TestRunner = Future<void> Function(List<String> testArgs, Map<String, String> environment);
TestRunner testRunner = _runTests;
void restoreTestRunner() {
testRunner = _runTests;
}
Future<void> _runTests(List<String> testArgs, String observatoryUri) async {
Future<void> _runTests(List<String> testArgs, Map<String, String> environment) async {
printTrace('Running driver tests.');
PackageMap.globalPackagesPath = fs.path.normalize(fs.path.absolute(PackageMap.globalPackagesPath));
......@@ -310,7 +346,7 @@ Future<void> _runTests(List<String> testArgs, String observatoryUri) async {
'--packages=${PackageMap.globalPackagesPath}',
'-rexpanded',
],
environment: <String, String>{'VM_SERVICE_URL': observatoryUri},
environment: environment,
);
if (result != 0) {
throwToolExit('Driver tests failed: $result', exitCode: result);
......
......@@ -11,9 +11,9 @@ dependencies:
# To update these, use "flutter update-packages --force-upgrade".
archive: 2.0.11
args: 1.5.2
dwds: 0.8.1
dwds: 0.8.5
completion: 0.2.1+1
coverage: 0.13.3+1
coverage: 0.13.3+3
crypto: 2.1.3
file: 5.1.0
http: 0.12.0+2
......@@ -46,7 +46,7 @@ dependencies:
test_core: 0.2.15
# Code generation dependencies
build_runner_core: 4.2.0
build_runner_core: 4.3.0
dart_style: 1.3.3
code_builder: 3.2.1
build: 1.2.2
......@@ -118,7 +118,7 @@ dev_dependencies:
test: 1.9.4
build_runner: 1.7.2
build_vm_compilers: 1.0.4
build_test: 0.10.10
build_test: 0.10.11
multi_server_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_preamble: 1.4.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -128,4 +128,4 @@ dartdoc:
# Exclude this package from the hosted API docs.
nodoc: true
# PUBSPEC CHECKSUM: de88
# PUBSPEC CHECKSUM: 6e90
......@@ -46,7 +46,7 @@ void main() {
appStarter = (DriveCommand command) {
throw 'Unexpected call to appStarter';
};
testRunner = (List<String> testArgs, String observatoryUri) {
testRunner = (List<String> testArgs, Map<String, String> environment) {
throw 'Unexpected call to testRunner';
};
appStopper = (DriveCommand command) {
......@@ -171,8 +171,16 @@ void main() {
appStarter = expectAsync1((DriveCommand command) async {
return LaunchResult.succeeded();
});
testRunner = expectAsync2((List<String> testArgs, String observatoryUri) async {
testRunner = expectAsync2((List<String> testArgs, Map<String, String> environment) async {
expect(testArgs, <String>[testFile]);
// VM_SERVICE_URL is not set by drive command arguments
expect(environment, <String, String>{
'VM_SERVICE_URL': 'null',
'SELENIUM_PORT': '4567',
'BROWSER_NAME': 'firefox',
'BROWSER_DIMENSION': '1024,768',
'HEADLESS': 'false',
});
return null;
});
appStopper = expectAsync1((DriveCommand command) async {
......@@ -187,6 +195,10 @@ void main() {
'drive',
'--target=$testApp',
'--no-pub',
'--no-headless',
'--driver-port=4567',
'--browser-name=firefox',
'--browser-dimension=1024,768',
];
await createTestCommandRunner(command).run(args);
expect(testLogger.errorText, isEmpty);
......@@ -204,7 +216,7 @@ void main() {
appStarter = expectAsync1((DriveCommand command) async {
return LaunchResult.succeeded();
});
testRunner = (List<String> testArgs, String observatoryUri) async {
testRunner = (List<String> testArgs, Map<String, String> environment) async {
throwToolExit(null, exitCode: 123);
};
appStopper = expectAsync1((DriveCommand command) async {
......@@ -361,7 +373,7 @@ void main() {
testApp = fs.path.join(tempDir.path, 'test', 'e2e.dart');
testFile = fs.path.join(tempDir.path, 'test_driver', 'e2e_test.dart');
testRunner = (List<String> testArgs, String observatoryUri) async {
testRunner = (List<String> testArgs, Map<String, String> environment) async {
throwToolExit(null, exitCode: 123);
};
appStopper = expectAsync1(
......@@ -494,7 +506,7 @@ void main() {
testApp = fs.path.join(tempDir.path, 'test', 'e2e.dart');
testFile = fs.path.join(tempDir.path, 'test_driver', 'e2e_test.dart');
testRunner = (List<String> testArgs, String observatoryUri) async {
testRunner = (List<String> testArgs, Map<String, String> environment) async {
throwToolExit(null, exitCode: 123);
};
appStopper = expectAsync1(
......
......@@ -40,14 +40,16 @@ dependencies:
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
sync_http: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.2.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vector_math: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service_client: 0.2.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webdriver: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
xml: 3.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dev_dependencies:
mockito: 4.1.1
# PUBSPEC CHECKSUM: a765
# PUBSPEC CHECKSUM: 1daa
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment