[instrumentation_adapter] Add support for running tests with Flutter driver (#2050)
diff --git a/packages/instrumentation_adapter/CHANGELOG.md b/packages/instrumentation_adapter/CHANGELOG.md
index 73557c5..e3e890b 100644
--- a/packages/instrumentation_adapter/CHANGELOG.md
+++ b/packages/instrumentation_adapter/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.2
+
+* Added support for running tests using Flutter driver.
+
## 0.1.1
* Updates about using *androidx* library.
diff --git a/packages/instrumentation_adapter/README.md b/packages/instrumentation_adapter/README.md
index 81f5155..b2dad97 100644
--- a/packages/instrumentation_adapter/README.md
+++ b/packages/instrumentation_adapter/README.md
@@ -90,3 +90,15 @@
--results-bucket=<RESULTS_BUCKET> \
--results-dir=<RESULTS_DIRECTORY>
```
+
+## Flutter driver support
+
+`InstrumentationAdapterFlutterBinding` also reports test results to `FlutterDriver`
+when run on the command line via `flutter drive`.
+
+```dart
+ final FlutterDriver driver = await FlutterDriver.connect();
+ final String result = await driver.requestData(null, timeout: const Duration(minutes: 1));
+ driver.close();
+ exit(result == 'pass' ? 0 : 1);
+```
diff --git a/packages/instrumentation_adapter/lib/instrumentation_adapter.dart b/packages/instrumentation_adapter/lib/instrumentation_adapter.dart
index 81f8187..2ec16c4 100644
--- a/packages/instrumentation_adapter/lib/instrumentation_adapter.dart
+++ b/packages/instrumentation_adapter/lib/instrumentation_adapter.dart
@@ -2,6 +2,7 @@
// 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_test/flutter_test.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
@@ -16,9 +17,12 @@
tearDownAll(() async {
await _channel.invokeMethod<void>(
'allTestsFinished', <String, dynamic>{'results': _results});
+ if (!_allTestsPassed.isCompleted) _allTestsPassed.complete(true);
});
}
+ final Completer<bool> _allTestsPassed = Completer<bool>();
+
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null) {
InstrumentationAdapterFlutterBinding();
@@ -32,14 +36,46 @@
static Map<String, String> _results = <String, String>{};
+ // Emulates the Flutter driver extension, returning 'pass' or 'fail'.
+ @override
+ void initServiceExtensions() {
+ super.initServiceExtensions();
+ Future<Map<String, dynamic>> callback(Map<String, String> params) async {
+ final String command = params['command'];
+ Map<String, String> response;
+ switch (command) {
+ case 'request_data':
+ final bool allTestsPassed = await _allTestsPassed.future;
+ response = <String, String>{
+ 'message': allTestsPassed ? 'pass' : 'fail',
+ };
+ break;
+ case 'get_health':
+ response = <String, String>{'status': 'ok'};
+ break;
+ default:
+ throw UnimplementedError('$command is not implemented');
+ }
+ return <String, dynamic>{
+ 'isError': false,
+ 'response': response,
+ };
+ }
+
+ registerServiceExtension(name: 'driver', callback: callback);
+ }
+
@override
Future<void> runTest(Future<void> testBody(), VoidCallback invariantTester,
{String description = '', Duration timeout}) async {
// TODO(jackson): Report the results individually instead of all at once
// See https://github.com/flutter/flutter/issues/38985
+ final TestExceptionReporter valueBeforeTest = reportTestException;
reportTestException =
(FlutterErrorDetails details, String testDescription) {
_results[description] = 'failed';
+ _allTestsPassed.complete(false);
+ valueBeforeTest(details, testDescription);
};
await super.runTest(testBody, invariantTester,
description: description, timeout: timeout);