diff --git a/packages/instrumentation_adapter/CHANGELOG.md b/packages/instrumentation_adapter/CHANGELOG.md index 73557c5c704a..e3e890b30c23 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 81f515569ac5..b2dad9798593 100644 --- a/packages/instrumentation_adapter/README.md +++ b/packages/instrumentation_adapter/README.md @@ -90,3 +90,15 @@ gcloud firebase test android run --type instrumentation \ --results-bucket= \ --results-dir= ``` + +## 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 81f81872d950..2ec16c4ebe56 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 @@ class InstrumentationAdapterFlutterBinding tearDownAll(() async { await _channel.invokeMethod( 'allTestsFinished', {'results': _results}); + if (!_allTestsPassed.isCompleted) _allTestsPassed.complete(true); }); } + final Completer _allTestsPassed = Completer(); + static WidgetsBinding ensureInitialized() { if (WidgetsBinding.instance == null) { InstrumentationAdapterFlutterBinding(); @@ -32,14 +36,46 @@ class InstrumentationAdapterFlutterBinding static Map _results = {}; + // Emulates the Flutter driver extension, returning 'pass' or 'fail'. + @override + void initServiceExtensions() { + super.initServiceExtensions(); + Future> callback(Map params) async { + final String command = params['command']; + Map response; + switch (command) { + case 'request_data': + final bool allTestsPassed = await _allTestsPassed.future; + response = { + 'message': allTestsPassed ? 'pass' : 'fail', + }; + break; + case 'get_health': + response = {'status': 'ok'}; + break; + default: + throw UnimplementedError('$command is not implemented'); + } + return { + 'isError': false, + 'response': response, + }; + } + + registerServiceExtension(name: 'driver', callback: callback); + } + @override Future runTest(Future 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);