Annotate async expectations with awaitNotRequired (#2700)

Closes #2139

Asynchronous expectations which return a `Future` already use
`TestHandle.current.markPending()` so that test cases are not considered
complete until after the expectations are complete. Some uses will want
to `await` anyway to maintain execution order in tests, but it's valid
to "fire and forget" asynchronous expectations when execution order
doesn't matter. Annotate with `@awaitNotRequired` so this is explicit
and the `unawaited_futures` lint is suppressed at call sites.
diff --git a/pkgs/checks/CHANGELOG.md b/pkgs/checks/CHANGELOG.md
index 513d0f9..adf5b0d 100644
--- a/pkgs/checks/CHANGELOG.md
+++ b/pkgs/checks/CHANGELOG.md
@@ -12,6 +12,9 @@
   forward exceptions from that call.
 - Fix a bug when printing a failure message involving a value that returns an
   empty output from `toString()`.
+- Annotated async expectations with `@awaitNotRequired` since tests are safely
+  held open until expectations complete so it's not always necessary to
+  explicitly await them.
 
 ## 0.3.1
 
diff --git a/pkgs/checks/lib/src/extensions/async.dart b/pkgs/checks/lib/src/extensions/async.dart
index cee3d40..f1fc3f2 100644
--- a/pkgs/checks/lib/src/extensions/async.dart
+++ b/pkgs/checks/lib/src/extensions/async.dart
@@ -6,6 +6,7 @@
 import 'dart:convert';
 
 import 'package:async/async.dart';
+import 'package:meta/meta.dart' show awaitNotRequired;
 
 import '../../context.dart';
 
@@ -18,6 +19,7 @@
   ///
   /// The returned future will complete when the subject future has completed,
   /// and [completionCondition] has optionally been checked.
+  @awaitNotRequired
   Future<void> completes([AsyncCondition<T>? completionCondition]) {
     return context.nestAsync<T>(() => ['completes to a value'], (actual) async {
       try {
@@ -79,6 +81,7 @@
   ///
   /// The returned future will complete when the subject future has completed,
   /// and [errorCondition] has optionally been checked.
+  @awaitNotRequired
   Future<void> throws<E extends Object>([AsyncCondition<E>? errorCondition]) {
     return context.nestAsync<E>(
       () => ['completes to an error${E == Object ? '' : ' of type $E'}'],
@@ -113,6 +116,7 @@
   /// Calls [Context.expectAsync] and wraps [predicate] with a transaction.
   ///
   /// The transaction is committed if the check passes, or rejected if it fails.
+  @awaitNotRequired
   Future<void> _expectAsync(
     Iterable<String> Function() clause,
     FutureOr<Rejection?> Function(StreamQueue<T>) predicate,
@@ -142,6 +146,7 @@
   ///
   /// The returned future will complete when the stream has emitted, errored, or
   /// ended, and the [emittedCondition] has optionally been checked.
+  @awaitNotRequired
   Future<void> emits([AsyncCondition<T>? emittedCondition]) {
     return context.nestAsync<T>(() => ['emits a value'], (actual) async {
       if (!await actual.hasNext) {
@@ -180,6 +185,7 @@
   ///
   /// The returned future will complete when the stream has emitted, errored, or
   /// ended, and the [errorCondition] has optionally been checked.
+  @awaitNotRequired
   Future<void> emitsError<E extends Object>([
     AsyncCondition<E>? errorCondition,
   ]) {
@@ -228,6 +234,7 @@
   /// state.
   /// If this expectation succeeds, consumes the matching event and all prior
   /// events.
+  @awaitNotRequired
   Future<void> emitsThrough(AsyncCondition<T> condition) async {
     await _expectAsync(
       () => [
@@ -267,6 +274,7 @@
   /// state.
   /// If this expectation succeeds, consumes as many events from the source
   /// stream as are consumed by all the conditions.
+  @awaitNotRequired
   Future<void> inOrder(
     Iterable<AsyncCondition<StreamQueue<T>>> conditions,
   ) async {
@@ -325,6 +333,7 @@
   /// If this expectation succeeds, consumes the same events from the source
   /// queue as the satisfied condition. If multiple conditions are satisfied,
   /// chooses the condition which consumed the most events.
+  @awaitNotRequired
   Future<void> anyOf(Iterable<AsyncCondition<StreamQueue<T>>> conditions) {
     conditions = conditions.toList();
     if (conditions.isEmpty) {
@@ -412,6 +421,7 @@
   /// state.
   /// If this expectation succeeds, consumes all the events that did not satisfy
   /// [condition] until the end of the stream.
+  @awaitNotRequired
   Future<void> neverEmits(AsyncCondition<T> condition) async {
     await _expectAsync(
       () => ['never emits a value that:', ...describe(condition)],
@@ -440,6 +450,7 @@
   ///
   /// If a non-matching event is emitted, no events are consumed.
   /// If a matching event is emitted, that event is consumed.
+  @awaitNotRequired
   Future<void> mayEmit(AsyncCondition<T> condition) {
     return context.expectAsync(
       () {
@@ -472,6 +483,7 @@
   /// - A non-matching event is emitted.
   /// - An error is emitted.
   /// - The stream closes.
+  @awaitNotRequired
   Future<void> mayEmitMultiple(AsyncCondition<T> condition) {
     return context.expectAsync(
       () {
@@ -503,6 +515,7 @@
   ///
   /// If this expectation fails, the source queue will be left in its original
   /// state, the event or error that caused it to fail will not be consumed.
+  @awaitNotRequired
   Future<void> isDone() async {
     await _expectAsync(() => ['is done'], (actual) async {
       if (!await actual.hasNext) return null;