Skip to content

Conversation

victoreronmosele
Copy link
Contributor

@victoreronmosele victoreronmosele commented Nov 9, 2023

This PR enables the flutter screenshot to work outside a Flutter project.

This works by enabling ScreenshotCommand to find target devices not supported by the project.

Before:

$ cd $HOME # not a Flutter directory

$ flutter screenshot

No devices found yet. Checking for wireless devices...

No supported devices connected.

The following devices were found, but are not supported by this project:
sdk gphone64 arm64 (mobile) • emulator-5554 • android-arm64  • Android 13 (API 33) (emulator)
macOS (desktop)             • macos         • darwin-arm64   • macOS 13.3.1 22E772610a darwin-arm64
Chrome (web)                • chrome        • web-javascript • Google Chrome 119.0.6045.105
If you would like your app to run on android or macos or web, consider running `flutter create .` to generate projects for these platforms.
Must have a connected device for screenshot type device

After:

$ cd $HOME # not a Flutter directory

$ flutter_source screenshot

Screenshot written to flutter_01.png (313kB).

Fixes #115790

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I signed the CLA.
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@github-actions github-actions bot added the tool Affects the "flutter" command-line tool. See also t: labels. label Nov 9, 2023
@victoreronmosele victoreronmosele force-pushed the flutter_screenshot_work_outside_project_dirs branch from 7ba84ce to ed8d6cd Compare November 9, 2023 18:36
@victoreronmosele victoreronmosele marked this pull request as ready for review November 9, 2023 19:40
@victoreronmosele victoreronmosele force-pushed the flutter_screenshot_work_outside_project_dirs branch from ed8d6cd to 36b164d Compare November 9, 2023 20:00
@@ -120,6 +120,15 @@ class ScreenshotCommand extends FlutterCommand {
: FlutterCommandResult.fail();
}

@override
Future<Device?> findTargetDevice({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than this, we could just pass includeDevicesUnsupportedByProject: true at line 81, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @christopherfujino. Agreed.

I just tested it and I'll update and push the change shortly.

@github-actions github-actions bot added a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels. engine flutter/engine repository. See also e: labels. f: material design flutter/packages/flutter/material repository. d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos f: integration_test The flutter/packages/integration_test plugin labels Nov 9, 2023
@victoreronmosele victoreronmosele force-pushed the flutter_screenshot_work_outside_project_dirs branch from 102f819 to 36b164d Compare November 9, 2023 23:47

testDeviceManager.devices = <Device>[deviceUnsupportedForProject];

expect(() => createTestCommandRunner(command).run(<String>['screenshot']), returnsNormally);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think returnsNormally is an async matcher, and thus it will not catch if the command fails asynchronously. why don't you just await the call, without an expects around it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I await the call without the expect, and I use findTargetDevice(includeDevicesUnsupportedByProject: false) in line 81 to make the call fail, the test fails but does not complete, and I have to Cntrl-C to exit it.

    testUsingContext('should not throw for a single device', () async {
      final ScreenshotCommand command = ScreenshotCommand(fs: MemoryFileSystem.test());

      final _ScreenshotDevice deviceUnsupportedForProject = _ScreenshotDevice(isSupportedForProject: false);

      testDeviceManager.devices = <Device>[deviceUnsupportedForProject];

      await createTestCommandRunner(command).run(<String>['screenshot']);
    }, overrides: <Type, Generator>{
      DeviceManager: () => testDeviceManager,
    });
Logs:

Test process is stuck after this:

00:00 +8: Screenshot for devices unsupported for project should not throw for a single device
UnimplementedError: targetPlatform
#0      Fake.noSuchMethod (package:test_api/src/frontend/fake.dart:50:5)
#1      _ScreenshotDevice.targetPlatform (file:///Users/victoreronmosele/development/mobile_projects/flutter_projects/flutter_contributions/flutter/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart:160:7)
#2      Device.descriptions (package:flutter_tools/src/device.dart:821:58)
#3      TargetDevices._printUnsupportedDevice (package:flutter_tools/src/runner/target_devices.dart:333:23)
#4      TargetDevices._handleNoDevices (package:flutter_tools/src/runner/target_devices.dart:219:11)
<asynchronous suspension>
#5      FlutterCommand.findTargetDevice (package:flutter_tools/src/runner/flutter_command.dart:1766:32)
<asynchronous suspension>
#6      ScreenshotCommand._validateOptions (package:flutter_tools/src/commands/screenshot.dart:81:18)
<asynchronous suspension>
#7      ScreenshotCommand.verifyThenRunCommand (package:flutter_tools/src/commands/screenshot.dart:100:5)
<asynchronous suspension>
#8      FlutterCommand.run.<anonymous closure> (package:flutter_tools/src/runner/flutter_command.dart:1374:27)
<asynchronous suspension>
#9      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
<asynchronous suspension>
#10     CommandRunner.runCommand (package:args/command_runner.dart:212:13)
<asynchronous suspension>
#11     FlutterCommandRunner.runCommand.<anonymous closure> (package:flutter_tools/src/runner/flutter_command_runner.dart:349:9)
<asynchronous suspension>
#12     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
<asynchronous suspension>
#13     FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:294:5)
<asynchronous suspension>
#14     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
<asynchronous suspension>
#15     main.<anonymous closure>.<anonymous closure> (file:///Users/victoreronmosele/development/mobile_projects/flutter_projects/flutter_contributions/flutter/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart:141:7)
<asynchronous suspension>
#16     testUsingContext.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (file:///Users/victoreronmosele/development/mobile_projects/flutter_projects/flutter_contributions/flutter/packages/flutter_tools/test/src/context.dart:141:26)
<asynchronous suspension>
#17     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
<asynchronous suspension>
#18     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
<asynchronous suspension>
#19     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
<asynchronous suspension>
#20     testUsingContext.<anonymous closure> (file:///Users/victoreronmosele/development/mobile_projects/flutter_projects/flutter_contributions/flutter/packages/flutter_tools/test/src/context.dart:102:5)
<asynchronous suspension>
#21     Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:215:9)
<asynchronous suspension>
#22     Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:213:7)
<asynchronous suspension>
#23     Invoker._waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:258:9)
<asynchronous suspension>

00:00 +8 -1: Screenshot for devices unsupported for project should not throw for a single device [E]
  UnimplementedError: targetPlatform
  package:test_api                                                 Fake.noSuchMethod
  test/commands.shard/hermetic/screenshot_command_test.dart 160:7  _ScreenshotDevice.targetPlatform
  package:flutter_tools/src/device.dart 821:58                     Device.descriptions
  package:flutter_tools/src/runner/target_devices.dart 333:23      TargetDevices._printUnsupportedDevice
  package:flutter_tools/src/runner/target_devices.dart 219:11      TargetDevices._handleNoDevices
  ===== asynchronous gap ===========================
  dart:async                                                       _CustomZone.registerBinaryCallback
  package:flutter_tools/src/base/context.dart 150:19               AppContext.run.<fn>
  dart:async                                                       runZoned
  package:flutter_tools/src/base/context.dart 149:12               AppContext.run
  test/src/context.dart 130:30                                     testUsingContext.<fn>.<fn>.<fn>.<fn>
  dart:async                                                       runZonedGuarded
  test/src/context.dart 128:18                                     testUsingContext.<fn>.<fn>.<fn>
  package:flutter_tools/src/base/context.dart 150:29               AppContext.run.<fn>
  dart:async                                                       runZoned
  package:flutter_tools/src/base/context.dart 149:12               AppContext.run
  test/src/context.dart 103:22                                     testUsingContext.<fn>.<fn>
  package:flutter_tools/src/context_runner.dart 84:18              runInContext.runnerWrapper
  ===== asynchronous gap ===========================
  dart:async                                                       _CustomZone.registerUnaryCallback
  package:flutter_tools/src/context_runner.dart 83:20              runInContext.runnerWrapper
  package:flutter_tools/src/base/context.dart 150:29               AppContext.run.<fn>
  dart:async                                                       runZoned
  package:flutter_tools/src/base/context.dart 149:12               AppContext.run
  package:flutter_tools/src/context_runner.dart 87:18              runInContext
  test/src/context.dart 102:11                                     testUsingContext.<fn>
  test/src/common.dart 183:18                                      test.<fn>

After Ctrl-C:

^C
To run this test again: /Users/victoreronmosele/development/mobile_projects/flutter_projects/flutter_contributions/flutter/bin/cache/dart-sdk/bin/dart test /Users/victoreronmosele/development/mobile_projects/flutter_projects/flutter_contributions/flutter/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart -p vm --plain-name 'Screenshot for devices unsupported for project should not throw for a single device'
unhandled error during finalization of test:
/Users/victoreronmosele/development/mobile_projects/flutter_projects/flutter_contributions/flutter/packages/flutter_tools/test/commands.shard/herme
tic/screenshot_command_test.dart
TestDeviceException(Shell subprocess terminated by ^C (SIGINT, -2).)
#0      FlutterTesterTestDevice.finished (package:flutter_tools/src/test/flutter_tester_device.dart:241:5)
<asynchronous suspension>
#1      FlutterTesterTestDevice.kill (package:flutter_tools/src/test/flutter_tester_device.dart:223:5)
<asynchronous suspension>
#2      FlutterPlatform._startTest.<anonymous closure> (package:flutter_tools/src/test/flutter_platform.dart:510:9)
<asynchronous suspension>
#3      FlutterPlatform._startTest (package:flutter_tools/src/test/flutter_platform.dart:566:11)
<asynchronous suspension>


unhandled error during finalization of test:
/Users/victoreronmosele/development/mobile_projects/flutter_projects/flutter_contributions/flutter/packages/flutter_tools/test/commands.shard/herme
tic/screenshot_command_test.dart
PathNotFoundException: Deletion failed, path = '/var/folders/8n/qpsf1kw9371gl1_vvgt4_05r0000gn/T/flutter_tools.rcRMz1/flutter_test_listener.dbAeH2'
(OS Error: No such file or directory, errno = 2)
#0      _Directory._deleteSync (dart:io/directory_impl.dart:193:7)
#1      FileSystemEntity.deleteSync (dart:io/file_system_entity.dart:423:7)
#2      ForwardingFileSystemEntity.deleteSync (package:file/src/forwarding/forwarding_file_system_entity.dart:70:16)
#3      FlutterPlatform._createListenerDart.<anonymous closure> (package:flutter_tools/src/test/flutter_platform.dart:602:15)
#4      FlutterPlatform._startTest (package:flutter_tools/src/test/flutter_platform.dart:566:26)
<asynchronous suspension>


02:39 +8 -2: loading /Users/victoreronmosele/development/mobile_projects/flutter_projects/flutter_contributions/flutter/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart [E]
  Error: the Dart compiler exited unexpectedly.
  package:flutter_tools/src/base/common.dart 10:3  throwToolExit
  package:flutter_tools/src/compile.dart 896:9     DefaultResidentCompiler._compile.<fn>
  dart:async/zone.dart 1407:47                     _rootRunUnary
  dart:async/zone.dart 1308:19                     _CustomZone.runUnary
  dart:async/future_impl.dart 838:45               Future._propagateToListeners.handleValueCallback
  dart:async/future_impl.dart 867:13               Future._propagateToListeners
  dart:async/future_impl.dart 643:5                Future._completeWithValue
  dart:async/future_impl.dart 713:7                Future._asyncCompleteWithValue.<fn>
  dart:async/zone.dart 1399:13                     _rootRun
  dart:async/zone.dart 1301:19                     _CustomZone.run
  dart:async/zone.dart 1209:7                      _CustomZone.runGuarded
  dart:async/zone.dart 1249:23                     _CustomZone.bindCallbackGuarded.<fn>
  dart:async/schedule_microtask.dart 40:21         _microtaskLoop
  dart:async/schedule_microtask.dart 49:5          _startMicrotaskLoop
  dart:isolate-patch/isolate_patch.dart 118:13     _runPendingImmediateCallback
  dart:isolate-patch/isolate_patch.dart 185:5      _RawReceivePort._handleMessage

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an unrelated tool bug, any test failure will hang the process and require killing the process.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. I'll proceed with the change to use await then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated this.

testDeviceManager = _TestDeviceManager(logger: BufferLogger.test());
});

testUsingContext('should not throw', () async {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you also add a test for when there are multiple devices? I'm guessing it should tool exit with a message to pass the -d option.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a test for this.

@github-actions github-actions bot added a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) f: cupertino flutter/packages/flutter/cupertino repository f: gestures flutter/packages/flutter/gestures repository. a: desktop Running on desktop labels Nov 10, 2023
@victoreronmosele victoreronmosele force-pushed the flutter_screenshot_work_outside_project_dirs branch from cdfd635 to 596c923 Compare November 10, 2023 22:33
Copy link
Contributor

@christopherfujino christopherfujino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM thanks for this fix!

@andrewkolos
Copy link
Contributor

Merged master in to try to unstuck the Google Testing check

Copy link
Contributor

@andrewkolos andrewkolos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@christopherfujino christopherfujino added the autosubmit Merge PR when tree becomes green via auto submit App label Nov 17, 2023
@auto-submit auto-submit bot merged commit e9de448 into flutter:master Nov 17, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Nov 17, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Nov 17, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Nov 17, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Nov 18, 2023
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Nov 18, 2023
flutter/flutter@53a57ad...6cf9ab0

2023-11-18 [email protected] Roll Flutter Engine from 53c4fde7732b to d7af5fb60b4c (2 revisions) (flutter/flutter#138668)
2023-11-18 [email protected] Update release.yml (flutter/flutter#138561)
2023-11-18 [email protected] Roll Flutter Engine from 384f75061257 to 53c4fde7732b (2 revisions) (flutter/flutter#138660)
2023-11-18 [email protected] Roll Flutter Engine from 5f40c9f49f88 to 384f75061257 (2 revisions) (flutter/flutter#138658)
2023-11-18 [email protected] Roll Flutter Engine from 66f764a16610 to 5f40c9f49f88 (1 revision) (flutter/flutter#138655)
2023-11-18 [email protected] Roll Flutter Engine from 1d2ee544c5e5 to 66f764a16610 (1 revision) (flutter/flutter#138652)
2023-11-18 [email protected] Roll Flutter Engine from c38272b5e036 to 1d2ee544c5e5 (3 revisions) (flutter/flutter#138650)
2023-11-17 [email protected] Roll Flutter Engine from e010f17eeb10 to c38272b5e036 (4 revisions) (flutter/flutter#138647)
2023-11-17 [email protected] Update links and surrounding text for new `main-api` docs (flutter/flutter#138602)
2023-11-17 [email protected] Roll Flutter Engine from 141a01c5c70b to e010f17eeb10 (2 revisions) (flutter/flutter#138643)
2023-11-17 [email protected] Roll Flutter Engine from 90c3ada3682c to 141a01c5c70b (16 revisions) (flutter/flutter#138637)
2023-11-17 [email protected] Roll Flutter Engine from 5064aeff00de to 90c3ada3682c (9 revisions) (flutter/flutter#138599)
2023-11-17 [email protected] Fix NoSplash not being disposed (flutter/flutter#138542)
2023-11-17 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Introduce `AnimationStyle`" (flutter/flutter#138628)
2023-11-17 [email protected] Enable `flutter screenshot` outside Flutter project directory (flutter/flutter#138160)
2023-11-17 [email protected] Roll Flutter Engine from aae07e989b0a to 5064aeff00de (2 revisions) (flutter/flutter#138585)
2023-11-16 [email protected] Improves output file path logic in Android analyze (flutter/flutter#136981)
2023-11-16 [email protected] Turn off leak tracker in master to make found leaks not blocking. (flutter/flutter#138567)
2023-11-16 [email protected] Roll Flutter Engine from 094a3383a406 to aae07e989b0a (2 revisions) (flutter/flutter#138574)
2023-11-16 [email protected] Enable the silent flag for invalid string exceptions when building a TextSpan (flutter/flutter#138564)
2023-11-16 [email protected] Roll Flutter Engine from 22baa83db63b to 094a3383a406 (13 revisions) (flutter/flutter#138568)
2023-11-16 [email protected] #60704: Pass cert for TLS localhost connection (flutter/flutter#106635)
2023-11-16 [email protected] Bump cupertino_icons to 1.0.6 (flutter/flutter#136962)
2023-11-16 [email protected] Fix sliver persistent header expand animation (flutter/flutter#137913)
2023-11-16 [email protected] Reduce animations further when --no-cli-animations is set. (flutter/flutter#133598)
2023-11-16 [email protected] Roll Flutter Engine from 0c57a50810e8 to 22baa83db63b (4 revisions) (flutter/flutter#138560)
2023-11-16 [email protected] Introduce `AnimationStyle` (flutter/flutter#137945)
2023-11-16 [email protected] Just use string interpolation for ws url for tests (flutter/flutter#138235)
2023-11-16 [email protected] Adding new packages to the first-party package issue template (flutter/flutter#138540)
2023-11-16 [email protected] Roll Packages from 0cd2378 to 07b4b29 (3 revisions) (flutter/flutter#138549)
2023-11-16 [email protected] Roll Flutter Engine from 2e9f0df868b3 to 0c57a50810e8 (1 revision) (flutter/flutter#138546)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: accessibility Accessibility, e.g. VoiceOver or TalkBack. (aka a11y) a: desktop Running on desktop a: text input Entering text in a text field or keyboard related problems autosubmit Merge PR when tree becomes green via auto submit App d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos engine flutter/engine repository. See also e: labels. f: cupertino flutter/packages/flutter/cupertino repository f: gestures flutter/packages/flutter/gestures repository. f: integration_test The flutter/packages/integration_test plugin f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. tool Affects the "flutter" command-line tool. See also t: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

flutter screenshot should not require being run from a Flutter project directory
3 participants