Allow some async work in main with global declarer (#1314)

When a test script is run directly without the test runner creating a
wrapping script there is a global `Declarer` which gets instantiated
during the first interaction with the test framework, such as a call to
`group` or `test`. This would wait a microtask to start running the
declared test cases, but would not work with a `main` that did other
async work before declaring more tests. We can't support arbitrary async
waits because we don't have a consistent signal that the `main` work is
done, so use `pumpEventQueue` as a best effort.
diff --git a/pkgs/test/test/runner/runner_test.dart b/pkgs/test/test/runner/runner_test.dart
index 224fdc2..697917e 100644
--- a/pkgs/test/test/runner/runner_test.dart
+++ b/pkgs/test/test/runner/runner_test.dart
@@ -362,6 +362,34 @@
     });
   });
 
+  group('runs successful tests with async setup', () {
+    setUp(() async {
+      await d.file('test.dart', '''
+        import 'package:test/test.dart';
+
+        void main() async {
+          test("success 1", () {});
+
+          await () async {};
+
+          test("success 2", () {});
+        }
+      ''').create();
+    });
+
+    test('defined in a single file', () async {
+      var test = await runTest(['test.dart']);
+      expect(test.stdout, emitsThrough(contains('+2: All tests passed!')));
+      await test.shouldExit(0);
+    });
+
+    test('directly', () async {
+      var test = await runDart(['test.dart']);
+      expect(test.stdout, emitsThrough(contains('All tests passed!')));
+      await test.shouldExit(0);
+    });
+  });
+
   group('runs failing tests', () {
     test('defaults to chaining stack traces', () async {
       await d.file('test.dart', _asyncFailure).create();
diff --git a/pkgs/test_core/lib/test_core.dart b/pkgs/test_core/lib/test_core.dart
index 8a31a76..af2357e 100644
--- a/pkgs/test_core/lib/test_core.dart
+++ b/pkgs/test_core/lib/test_core.dart
@@ -14,6 +14,7 @@
 import 'package:test_api/src/backend/declarer.dart'; // ignore: implementation_imports
 import 'package:test_api/src/backend/invoker.dart'; // ignore: implementation_imports
 import 'package:test_api/src/frontend/timeout.dart'; // ignore: implementation_imports
+import 'package:test_api/src/frontend/utils.dart'; // ignore: implementation_imports
 import 'package:test_api/src/utils.dart'; // ignore: implementation_imports
 
 import 'src/runner/engine.dart';
@@ -48,10 +49,13 @@
 
   // Since there's no Zone-scoped declarer, the test file is being run directly.
   // In order to run the tests, we set up our own Declarer via
-  // [_globalDeclarer], and schedule a microtask to run the tests once they're
-  // finished being defined.
+  // [_globalDeclarer], and pump the event queue as a best effort to wait for
+  // all tests to be defined before starting them.
   _globalDeclarer = Declarer();
-  scheduleMicrotask(() async {
+
+  () async {
+    await pumpEventQueue();
+
     var suite = RunnerSuite(const PluginEnvironment(), SuiteConfiguration.empty,
         _globalDeclarer!.build(), SuitePlatform(Runtime.vm, os: currentOSGuess),
         path: p.prettyUri(Uri.base));
@@ -67,7 +71,8 @@
     if (success == true) return null;
     print('');
     unawaited(Future.error('Dummy exception to set exit code.'));
-  });
+  }();
+
   return _globalDeclarer!;
 }