[flutter_plugin_tools] Work around banner in drive-examples (#4142)
* [flutter_plugin_tools] Work around banner in drive-examples
Strip off any unexpected output before parsing `flutter devices
--machine` output. Works around a bug in the Flutter tool that can
result in banners being printed in `--machine` mode.
Fixes https://github.com/flutter/flutter/issues/86052
diff --git a/script/tool/CHANGELOG.md b/script/tool/CHANGELOG.md
index 9e9538c..3f31a49 100644
--- a/script/tool/CHANGELOG.md
+++ b/script/tool/CHANGELOG.md
@@ -9,6 +9,7 @@
immediately abort the test.
- Deprecated `--plugins` in favor of new `--packages`. `--plugins` continues to
work for now, but will be removed in the future.
+- Make `drive-examples` device detection robust against Flutter tool banners.
## 0.3.0
diff --git a/script/tool/lib/src/drive_examples_command.dart b/script/tool/lib/src/drive_examples_command.dart
index 1e19535..df74119 100644
--- a/script/tool/lib/src/drive_examples_command.dart
+++ b/script/tool/lib/src/drive_examples_command.dart
@@ -208,9 +208,14 @@
return deviceIds;
}
+ String output = result.stdout as String;
+ // --machine doesn't currently prevent the tool from printing banners;
+ // see https://github.com/flutter/flutter/issues/86055. This workaround
+ // can be removed once that is fixed.
+ output = output.substring(output.indexOf('['));
+
final List<Map<String, dynamic>> devices =
- (jsonDecode(result.stdout as String) as List<dynamic>)
- .cast<Map<String, dynamic>>();
+ (jsonDecode(output) as List<dynamic>).cast<Map<String, dynamic>>();
for (final Map<String, dynamic> deviceInfo in devices) {
final String targetPlatform =
(deviceInfo['targetPlatform'] as String?) ?? '';
diff --git a/script/tool/test/drive_examples_command_test.dart b/script/tool/test/drive_examples_command_test.dart
index d22d95f..681a9e0 100644
--- a/script/tool/test/drive_examples_command_test.dart
+++ b/script/tool/test/drive_examples_command_test.dart
@@ -44,13 +44,22 @@
void setMockFlutterDevicesOutput({
bool hasIosDevice = true,
bool hasAndroidDevice = true,
+ bool includeBanner = false,
}) {
+ const String updateBanner = '''
+╔════════════════════════════════════════════════════════════════════════════╗
+║ A new version of Flutter is available! ║
+║ ║
+║ To update to the latest version, run "flutter upgrade". ║
+╚════════════════════════════════════════════════════════════════════════════╝
+''';
final List<String> devices = <String>[
if (hasIosDevice) '{"id": "$_fakeIosDevice", "targetPlatform": "ios"}',
if (hasAndroidDevice)
'{"id": "$_fakeAndroidDevice", "targetPlatform": "android-x86"}',
];
- final String output = '''[${devices.join(',')}]''';
+ final String output =
+ '''${includeBanner ? updateBanner : ''}[${devices.join(',')}]''';
final MockProcess mockDevicesProcess = MockProcess.succeeding();
mockDevicesProcess.stdoutController.close(); // ignore: unawaited_futures
@@ -113,6 +122,32 @@
);
});
+ test('handles flutter tool banners when checking devices', () async {
+ createFakePlugin(
+ 'plugin',
+ packagesDir,
+ extraFiles: <String>[
+ 'example/test_driver/integration_test.dart',
+ 'example/integration_test/foo_test.dart',
+ ],
+ platformSupport: <String, PlatformSupport>{
+ kPlatformIos: PlatformSupport.inline,
+ },
+ );
+
+ setMockFlutterDevicesOutput(includeBanner: true);
+ final List<String> output =
+ await runCapturingPrint(runner, <String>['drive-examples', '--ios']);
+
+ expect(
+ output,
+ containsAllInOrder(<Matcher>[
+ contains('Running for plugin'),
+ contains('No issues found!'),
+ ]),
+ );
+ });
+
test('fails for iOS if getting devices fails', () async {
// Simulate failure from `flutter devices`.
processRunner.mockProcessesForExecutable['flutter'] = <io.Process>[