@@ -246,29 +246,32 @@ Future<Object?> _invokeSymbolIfExists(
246246/// - The test fails by throwing an exception
247247/// - The test returns a future which completes with an error.
248248/// - An exception is thrown to the zone handler from a timer task.
249- Future <Object ?>? _runFailingTest (ClassMirror classMirror, Symbol symbol) {
250- var passed = false ;
251- return runZonedGuarded (() {
249+ Future <void > _runFailingTest (ClassMirror classMirror, Symbol symbol) async {
250+ _FailedTestResult ? result;
251+
252+ await runZonedGuarded (() {
252253 // ignore: void_checks
253254 return Future .sync (() => _runTest (classMirror, symbol)).then <void >((_) {
254- passed = true ;
255- test_package.fail ('Test passed - expected to fail.' );
255+ // We can't throw async exceptions inside here because `runZoneGuarded`
256+ // will never complete (see docs on `runZonedGuarded`), so we need to
257+ // capture this state and throw later if there wasn't otherwise an
258+ // exception.
259+
260+ // If we didn't already have a failure (eg. an unawaited exception) then
261+ // this successful completion is an unexpected pass state.
262+ result ?? = _FailedTestResult .pass;
256263 }).catchError ((Object e) {
257- // if passed, and we call fail(), rethrow this exception
258- if (passed) {
259- // ignore: only_throw_errors
260- throw e;
261- }
262- // otherwise, an exception is not a failure for _runFailingTest
264+ // an awaited exception is always expected failure.
265+ result = _FailedTestResult .expectedFail;
263266 });
264267 }, (e, st) {
265- // if passed, and we call fail(), rethrow this exception
266- if (passed) {
267- // ignore: only_throw_errors
268- throw e;
269- }
270- // otherwise, an exception is not a failure for _runFailingTest
268+ result = _FailedTestResult .expectedFail;
271269 });
270+
271+ // We can safely throw exceptions back outside of the error zone.
272+ if (result == _FailedTestResult .pass) {
273+ throw test_package.TestFailure ('Test passed - expected to fail.' );
274+ }
272275}
273276
274277Future <void > _runTest (ClassMirror classMirror, Symbol symbol) async {
@@ -389,6 +392,15 @@ class _Test {
389392 timeout = null ;
390393}
391394
395+ /// The result of a test that was expected to fail.
396+ enum _FailedTestResult {
397+ /// The test (unexpectedly) passed.
398+ pass,
399+
400+ /// The test failed as expected.
401+ expectedFail,
402+ }
403+
392404extension on DeclarationMirror {
393405 test_package.TestLocation ? get testLocation {
394406 if (location case var location? ) {
0 commit comments