Repository: flutter
Issue: [test] pumpAndSettle() deadlocks unless there is some random runAsyc() call
Labels: a: tests,framework,d: api docs,has reproducible steps,P2,found in release: 3.7,found in release: 3.9,team-framework,triaged-framework

<!-- Thank you for using Flutter!

     If you are looking for support, please check out our documentation
     or consider asking a question on Stack Overflow:
      * https://flutter.dev/
      * https://api.flutter.dev/
      * https://stackoverflow.com/questions/tagged/flutter?sort=frequent

     If you have found a bug or if our documentation doesn't have an answer
     to what you're looking for, then fill out the template below. Please read
     our guide to filing a bug first: https://flutter.dev/docs/resources/bug-reports
-->

## Steps to Reproduce

<!-- You must include full steps to reproduce so that we can reproduce the problem. -->

1. Run `flutter create bug; cd bug`.
2. Create a new file `test/image_test.dart` with the following contents: <details><summary>Click to see the contents</summary>
   ```dart
   import 'dart:async' show Completer;
   import 'dart:convert' show Utf8Encoder;
   import 'dart:typed_data' show ByteData, Uint8List;
   import 'dart:ui' as ui;

   import 'package:flutter/foundation.dart' show SynchronousFuture;
   import 'package:flutter/material.dart';
   import 'package:flutter/services.dart' show CachingAssetBundle;
   import 'package:flutter_test/flutter_test.dart';

   void main() {
     testWidgets('shows progress indicator while initializing/loading',
         (WidgetTester tester) async {
       final completer = Completer<ui.Image>();

       final image = Image.asset(
         'image.png',
         bundle: TestAssetBundle(),
       );

       image.image.resolve(ImageConfiguration()).addListener(
             ImageStreamListener(
               (ImageInfo info, bool _) {
                 print('completed');
                 completer.complete(info.image);
               },
               onError: (dynamic error, StackTrace stackTrace) {
                 completer.completeError(error, stackTrace);
               },
             ),
           );

       // This piece of code doesn't really have anything to do with the test, and ideally it should not exist in this test.
       await tester.runAsync(() async {
         final codec =
             await ui.instantiateImageCodec(Uint8List.fromList(kTransparentImage));
         //await codec.getNextFrame(); // Uncomment this line to make the test pass.
       });

       await tester.pumpWidget(
         FutureBuilder<ui.Image>(
           future: completer.future,
           builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
             if (snapshot.hasData) {
               final info = snapshot.data;
               if (info.width > info.height) {
                 return RotatedBox(
                   quarterTurns: 1,
                   child: image,
                 );
               }
               return image;
             }
             if (snapshot.hasError) {
               final error = snapshot.error;
               final msg = 'Media could not be played: $error';
               return Text(msg);
             }
             // Waiting to complete
             return CircularProgressIndicator();
           },
         ),
       );

       expect(find.byType(CircularProgressIndicator), findsOneWidget);
       expect(find.byType(Image), findsNothing);

       print('pumpAndSettle()');
       await tester.pumpAndSettle();
       print('Settled');

       expect(find.byType(CircularProgressIndicator), findsNothing);
       expect(find.byType(Image), findsOneWidget);
     });
   }

   class TestAssetBundle extends CachingAssetBundle {
     @override
     Future<ByteData> load(String key) {
       if (key == 'AssetManifest.json') {
         return SynchronousFuture<ByteData>(
           ByteData.view(Uint8List.fromList(
             const Utf8Encoder().convert(
               '{"image.png": ["image.png"]}',
             ),
           ).buffer),
         );
       }
       final fileContents = Uint8List.fromList(kTransparentImage);
       return SynchronousFuture<ByteData>(ByteData.view(fileContents.buffer));
     }
   }

   const List<int> kTransparentImage = <int>[
     0x89,
     0x50,
     0x4E,
     0x47,
     0x0D,
     0x0A,
     0x1A,
     0x0A,
     0x00,
     0x00,
     0x00,
     0x0D,
     0x49,
     0x48,
     0x44,
     0x52,
     0x00,
     0x00,
     0x00,
     0x01,
     0x00,
     0x00,
     0x00,
     0x01,
     0x08,
     0x06,
     0x00,
     0x00,
     0x00,
     0x1F,
     0x15,
     0xC4,
     0x89,
     0x00,
     0x00,
     0x00,
     0x0A,
     0x49,
     0x44,
     0x41,
     0x54,
     0x78,
     0x9C,
     0x63,
     0x00,
     0x01,
     0x00,
     0x00,
     0x05,
     0x00,
     0x01,
     0x0D,
     0x0A,
     0x2D,
     0xB4,
     0x00,
     0x00,
     0x00,
     0x00,
     0x49,
     0x45,
     0x4E,
     0x44,
     0xAE
   ];
   ```
   </details>
3. Run `flutter test test/image_test.dart`.

**Expected results:** <!-- what did you want to see? -->

The test pass.

**Actual results:** <!-- what did you see? -->

The test fails because `pumpAndSettle()` times out.

**Extended explanation and context for this report:**


For a bit of context, I'm looking for a way to test a widget just like the one in this example. The widget just needs to show and image rotated depending on the image orientation (landscape or portrait). To do so, the only way I found to know the image dimentions was to `resolve()` the image, but then while I'm resolving it, I needed to do something with my widget, so I added the `CircularProgressIndicator`. Now I wanted to write a test to verify this behaviour: The widget first shows the progress indicator and when the loading is done, the image is shown instead.

I noticed then that `tester.pumpAndSettle()` was deadlocking (or timing out) so I started to read about the details on widget testing and found they are run in a so called `FakeAsync` environment. I tried to wrap all the test in a `tester.runAsync()` as some stackoverflow questions suggest, but it would still deadlock. I tried to expose somehow a future to flag when the image is ready as the `runAsync` docs suggest, but I never could overcome the deadlock. At some point I found out about `LiveTestWidgetsFlutterBinding` and used that, and it works, but I don't think that is a good way to do unit testing, so I keep looking for a reliable way to test my widget. So I thought about providing the image data myself somehow (ideally I would like to do it via the `AssetBundle`). I looked at [Flutter's `Image` widget tests](https://github.com/flutter/flutter/blob/master/packages/flutter/test/widgets/image_test.dart), and tried a couple of tricks in there, tried to copy the `TestImageProvider` and friends, but it got very messy and I don't know the inside outs of the Bundle/ImageProvider/etc. machinery to get it right (and I think I shouldn't need to do such an overkill task to test a simple widget). I finally thought about just *injecting* the image data I needed to get the dimensions myself, again mimicing what Flutter Image tests do (this is why you'll see some similarities in the test case), so I added the following lines, just before the `tester.pumpAndSettle()` call:

```dart
// This must be run with [WidgetTester.runAsync] since it performs real async
// work.
Future<ui.Image> createTestImage([List<int> bytes = kTransparentImage]) async {
  final codec = await ui.instantiateImageCodec(Uint8List.fromList(bytes));
  final frameInfo = await codec.getNextFrame();
  return frameInfo.image;
}

final img = await tester.runAsync(() async => await createTestImage());
completer.complete(img);      
```
But now my test failed with `Bad state: Future already completed` and this is when I tried removing the line `completer.complete(img);` and to my surprise the test case started to pass!


<details>
  <summary>Logs</summary>

<!--
      Run your application with `flutter run --verbose` and attach all the
      log output below between the lines with the backticks. If there is an
      exception, please see if the error message includes enough information
      to explain how to solve the issue.
-->

```console
$ flutter test --verbose test/image_test.dart
[ +101 ms] executing: [/home/luca/software/flutter/] git -c log.showSignature=false log -n 1
--pretty=format:%H
[  +31 ms] Exit code 0 from: git -c log.showSignature=false log -n 1 --pretty=format:%H
[        ] be9bc8cb3942bda5d8ef4e44b44616c470625e18
[        ] executing: [/home/luca/software/flutter/] git tag --contains HEAD
[ +162 ms] Exit code 0 from: git tag --contains HEAD
[        ] 1.21.0-9.1.pre
[   +9 ms] executing: [/home/luca/software/flutter/] git rev-parse --abbrev-ref --symbolic @{u}
[   +4 ms] Exit code 0 from: git rev-parse --abbrev-ref --symbolic @{u}
[        ] origin/beta
[        ] executing: [/home/luca/software/flutter/] git ls-remote --get-url origin
[   +3 ms] Exit code 0 from: git ls-remote --get-url origin
[        ] https://github.com/flutter/flutter.git
[  +31 ms] executing: [/home/luca/software/flutter/] git rev-parse --abbrev-ref HEAD
[   +4 ms] Exit code 0 from: git rev-parse --abbrev-ref HEAD
[        ] beta
[  +35 ms] Artifact Instance of 'AndroidMavenArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'AndroidGenSnapshotArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterWebSdk' is not required, skipping update.
[   +1 ms] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update.
[   +5 ms] Artifact Instance of 'MaterialFonts' is not required, skipping update.
[        ] Artifact Instance of 'GradleWrapper' is not required, skipping update.
[        ] Artifact Instance of 'AndroidMavenArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'AndroidGenSnapshotArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterWebSdk' is not required, skipping update.
[        ] Artifact Instance of 'FlutterSdk' is not required, skipping update.
[        ] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update.
[        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IosUsbArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FontSubsetArtifacts' is not required, skipping update.
[ +170 ms] Generating
/tmp/bug/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java
[  +36 ms] running test package with arguments: [-r, compact, --concurrency=6, --,
/tmp/bug/test/image_test.dart]
00:00 +0: loading /tmp/bug/test/image_test.dart                                                   [ +198 ms] test 0: starting test /tmp/bug/test/image_test.dart
[   +9 ms] test 0: starting shell process
[   +3 ms] Stopping scan for flutter_test_config.dart; found project root at /tmp/bug
[   +3 ms] Compiler will use the following file as its incremental dill file:
/tmp/flutter_tools.BIBYXF/flutter_test_compiler.KKWKFE/output.dill
[        ] Listening to compiler controller...
[   +3 ms] Compiling file:///tmp/flutter_tools.BIBYXF/flutter_test_listener.IUIOJS/listener.dart
[   +8 ms] /home/luca/software/flutter/bin/cache/dart-sdk/bin/dart --disable-dart-dev
/home/luca/software/flutter/bin/cache/artifacts/engine/linux-x64/frontend_server.dart.snapshot
--sdk-root /home/luca/software/flutter/bin/cache/artifacts/engine/common/flutter_patched_sdk/
--incremental --target=flutter --debugger-module-names --experimental-emit-debug-metadata
-Ddart.developer.causal_async_stacks=true --output-dill
/tmp/flutter_tools.BIBYXF/flutter_test_compiler.KKWKFE/output.dill --packages /tmp/bug/.packages
-Ddart.vm.profile=false -Ddart.vm.product=false
--bytecode-options=source-positions,local-var-info,debugger-stops,instance-field-initializers,keep-
unreachable-code,avoid-closure-call-instructions --enable-asserts --track-widget-creation
--initialize-from-dill /tmp/bug/build/testfile.dill.track.dill
[  +11 ms] <- compile file:///tmp/flutter_tools.BIBYXF/flutter_test_listener.IUIOJS/listener.dart
[ +917 ms] <- accept
[        ] <- reset
[        ] Compiling /tmp/flutter_tools.BIBYXF/flutter_test_listener.IUIOJS/listener.dart took
937ms
[   +2 ms] /home/luca/software/flutter/bin/cache/artifacts/engine/linux-x64/flutter_tester
--disable-observatory --enable-checked-mode --verify-entry-points --enable-software-rendering
--skia-deterministic-rendering --enable-dart-profiling --non-interactive --use-test-fonts
--packages=/tmp/bug/.packages
/tmp/flutter_tools.BIBYXF/flutter_test_listener.IUIOJS/listener.dart.dill
[   +1 ms] Using this directory for fonts configuration:
/tmp/flutter_tools.BIBYXF/flutter_test_fonts.LNGEHJ
[   +4 ms] test 0: awaiting initial result for pid 1218368
00:01 +0: loading /tmp/bug/test/image_test.dart                                                   [ +516 ms] test 0: process with pid 1218368 connected to test harness
[        ] test 0: awaiting test result for pid 1218368
00:01 +0: shows progress indicator while initializing/loading                                     
pumpAndSettle()
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following assertion was thrown running a test:
pumpAndSettle timed out

When the exception was thrown, this was the stack:
#0      WidgetTester.pumpAndSettle.<anonymous closure> (package:flutter_test/src/widget_tester.dart:633:11)
<asynchronous suspension>
#1      WidgetTester.pumpAndSettle.<anonymous closure> (package:flutter_test/src/widget_tester.dart)
#4      TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:72:41)
#5      WidgetTester.pumpAndSettle (package:flutter_test/src/widget_tester.dart:628:27)
#6      main.<anonymous closure> (file:///tmp/bug/test/image_test.dart:69:18)
<asynchronous suspension>
#7      main.<anonymous closure> (file:///tmp/bug/test/image_test.dart)
#8      testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:146:29)
<asynchronous suspension>
#9      testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart)
#10     TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:784:19)
<asynchronous suspension>
#13     TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:764:14)
#14     AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1173:24)
#15     FakeAsync.run.<anonymous closure>.<anonymous closure> (package:fake_async/fake_async.dart:178:54)
#20     withClock (package:clock/src/default.dart:48:10)
#21     FakeAsync.run.<anonymous closure> (package:fake_async/fake_async.dart:178:22)
#26     FakeAsync.run (package:fake_async/fake_async.dart:178:7)
#27     AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:1170:15)
#28     testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.dart:138:24)
#29     Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:175:19)
<asynchronous suspension>
#30     Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart)
#35     Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:173:13)
#36     Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:231:15)
#41     Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:228:5)
#42     Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:383:17)
<asynchronous suspension>
#43     Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart)
#48     Invoker._onRun.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:370:9)
#49     Invoker._guardIfGuarded (package:test_api/src/backend/invoker.dart:415:15)
#50     Invoker._onRun.<anonymous closure> (package:test_api/src/backend/invoker.dart:369:7)
#57     Invoker._onRun (package:test_api/src/backend/invoker.dart:368:11)
#58     LiveTestController.run (package:test_api/src/backend/live_test_controller.dart:153:11)
#59     RemoteListener._runLiveTest.<anonymous closure> (package:test_api/src/remote_listener.dart:256:16)
#64     RemoteListener._runLiveTest (package:test_api/src/remote_listener.dart:255:5)
#65     RemoteListener._serializeTest.<anonymous closure> (package:test_api/src/remote_listener.dart:208:7)
#83     _GuaranteeSink.add (package:stream_channel/src/guarantee_channel.dart:125:12)
#84     new _MultiChannel.<anonymous closure> (package:stream_channel/src/multi_channel.dart:159:31)
#88     CastStreamSubscription._onData (dart:_internal/async_cast.dart:85:11)
#122    new _WebSocketImpl._fromSocket.<anonymous closure> (dart:_http/websocket_impl.dart:1145:21)
#130    _WebSocketProtocolTransformer._messageFrameEnd (dart:_http/websocket_impl.dart:338:23)
#131    _WebSocketProtocolTransformer.add (dart:_http/websocket_impl.dart:232:46)
#141    _Socket._onData (dart:io-patch/socket_patch.dart:2043:41)
#150    new _RawSocket.<anonymous closure> (dart:io-patch/socket_patch.dart:1579:33)
#151    _NativeSocket.issueReadEvent.issue (dart:io-patch/socket_patch.dart:1075:14)
(elided 113 frames from dart:async and package:stack_trace)

The test description was:
  shows progress indicator while initializing/loading
════════════════════════════════════════════════════════════════════════════════════════════════════
00:03 +0 -1: shows progress indicator while initializing/loading [E]                              
  Test failed. See exception logs above.
  The test description was: shows progress indicator while initializing/loading
  
[+1785 ms] test 0: process with pid 1218368 no longer needed by test harness
[        ] test 0: cleaning up...
[        ] test 0: ensuring end-of-process for shell
[   +7 ms] test 0: deleting temporary directory
[   +3 ms] test 0: shutting down test harness socket server
[   +1 ms] test 0: finished
00:03 +0 -1: Some tests failed.                                                                   
[   +8 ms] Deleting /tmp/flutter_tools.BIBYXF/flutter_test_compiler.KKWKFE...
[   +3 ms] killing pid 1218360
[  +35 ms] Deleting /tmp/flutter_tools.BIBYXF/flutter_test_fonts.LNGEHJ...
[   +5 ms] test package returned with exit code 1
[  +12 ms] "flutter test" took 3,769ms.
[   +4 ms] 
           #0      throwToolExit (package:flutter_tools/src/base/common.dart:14:3)
           #1      TestCommand.runCommand (package:flutter_tools/src/commands/test.dart:281:7)
           <asynchronous suspension>
           #2      FlutterCommand.verifyThenRunCommand
           (package:flutter_tools/src/runner/flutter_command.dart:909:18)
           <asynchronous suspension>
           #3      FlutterCommand.run.<anonymous closure>
           (package:flutter_tools/src/runner/flutter_command.dart:787:33)
           <asynchronous suspension>
           #4      FlutterCommand.run.<anonymous closure>
           (package:flutter_tools/src/runner/flutter_command.dart)
           #5      AppContext.run.<anonymous closure>
(package:flutter_tools/src/base/context.dart:150:29)
           #6      _rootRun (dart:async/zone.dart:1190:13)
           #7      _CustomZone.run (dart:async/zone.dart:1093:19)
           #8      _runZoned (dart:async/zone.dart:1630:10)
           #9      runZoned (dart:async/zone.dart:1550:10)
           #10     AppContext.run (package:flutter_tools/src/base/context.dart:149:18)
           #11     FlutterCommand.run
(package:flutter_tools/src/runner/flutter_command.dart:776:20)
           #12     CommandRunner.runCommand (package:args/command_runner.dart:197:27)
           #13     FlutterCommandRunner.runCommand.<anonymous closure>
           (package:flutter_tools/src/runner/flutter_command_runner.dart:335:21)
           #14     _rootRunUnary (dart:async/zone.dart:1198:47)
           #15     _CustomZone.runUnary (dart:async/zone.dart:1100:19)
           #16     _FutureListener.handleValue (dart:async/future_impl.dart:143:18)
           #17     Future._propagateToListeners.handleValueCallback
(dart:async/future_impl.dart:696:45)
           #18     Future._propagateToListeners (dart:async/future_impl.dart:725:32)
           #19     Future._completeWithValue (dart:async/future_impl.dart:529:5)
           #20     _AsyncAwaitCompleter.complete (dart:async-patch/async_patch.dart:40:15)
           #21     _completeOnAsyncReturn (dart:async-patch/async_patch.dart:311:13)
           #22     FlutterVersion.checkFlutterVersionFreshness
(package:flutter_tools/src/version.dart)
           #23     _rootRunUnary (dart:async/zone.dart:1198:47)
           #24     _CustomZone.runUnary (dart:async/zone.dart:1100:19)
           #25     _FutureListener.handleValue (dart:async/future_impl.dart:143:18)
           #26     Future._propagateToListeners.handleValueCallback
(dart:async/future_impl.dart:696:45)
           #27     Future._propagateToListeners (dart:async/future_impl.dart:725:32)
           #28     Future._completeWithValue (dart:async/future_impl.dart:529:5)
           #29     Future._asyncCompleteWithValue.<anonymous closure>
(dart:async/future_impl.dart:567:7)
           #30     _rootRun (dart:async/zone.dart:1190:13)
           #31     _CustomZone.run (dart:async/zone.dart:1093:19)
           #32     _CustomZone.runGuarded (dart:async/zone.dart:997:7)
           #33     _CustomZone.bindCallbackGuarded.<anonymous closure>
(dart:async/zone.dart:1037:23)
           #34     _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
           #35     _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
           #36     _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:118:13)
           #37     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:169:5)
           
           
[   +6 ms] Running shutdown hooks
[        ] Shutdown hook priority 4
[        ] Shutdown hooks complete
[        ] exiting with code 1
```

<!--
     Run `flutter analyze` and attach any output of that command below.
     If there are any analysis errors, try resolving them before filing this issue.
-->

```console
$ flutter analyze
Analyzing bug...                                                        

   info • The value of the local variable 'codec' isn't used • test/image_test.dart:35:13 •
          unused_local_variable

1 issue found. (ran in 1.3s)
```
This only happens because the code to *fix* the tests is commented out.

<!-- Finally, paste the output of running `flutter doctor -v` here. -->

```console
$ flutter doctor -v
[✓] Flutter (Channel beta, 1.21.0-9.1.pre, on Linux, locale en_IE.UTF-8)
    • Flutter version 1.21.0-9.1.pre at /home/luca/software/flutter
    • Framework revision be9bc8cb39 (7 days ago), 2020-08-18 09:46:08 -0700
    • Engine revision 267070c17a
    • Dart version 2.10.0 (build 2.10.0-7.2.beta)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.0)
    • Android SDK at /home/luca/Android/Sdk
    • Platform android-30, build-tools 30.0.0
    • Java binary at: /home/luca/software/android-studio/jre/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • CHROME_EXECUTABLE = chromium

[✓] Android Studio (version 4.0)
    • Android Studio at /home/luca/software/android-studio
    • Flutter plugin version 48.1.2
    • Dart plugin version 193.7361
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[✓] Connected device (3 available)
    • LG H870 (mobile) • LGH8701d9f7a4 • android-arm64  • Android 9 (API 28)
    • Web Server (web) • web-server    • web-javascript • Flutter Tools
    • Chrome (web)     • chrome        • web-javascript • Chromium 83.0.4103.116 built on Debian bullseye/sid, running on Debian bullseye/sid

• No issues found!
```

</details>