runAsync<T> method
- Future<
T> callback()
Runs a callback
that performs real asynchronous work.
This is intended for callers who need to call asynchronous methods where the methods spawn isolates or OS threads and thus cannot be executed synchronously by calling pump.
The callback
must return a Future that completes to a value of type
T
.
If callback
completes successfully, this will return the future
returned by callback
.
If callback
completes with an error, the error will be caught by the
Flutter framework and made available via takeException, and this method
will return a future that completes with null
.
Re-entrant calls to this method are not allowed; callers of this method are required to wait for the returned future to complete before calling this method again. Attempts to do otherwise will result in a TestFailure error being thrown.
Implementation
@override
Future<T?> runAsync<T>(Future<T> Function() callback) {
assert(() {
if (_pendingAsyncTasks == null) {
return true;
}
fail(
'Reentrant call to runAsync() denied.\n'
'runAsync() was called, then before its future completed, it '
'was called again. You must wait for the first returned future '
'to complete before calling runAsync() again.'
);
}());
final Zone realAsyncZone = Zone.current.fork(
specification: ZoneSpecification(
scheduleMicrotask: (Zone self, ZoneDelegate parent, Zone zone, void Function() f) {
Zone.root.scheduleMicrotask(f);
},
createTimer: (Zone self, ZoneDelegate parent, Zone zone, Duration duration, void Function() f) {
return Zone.root.createTimer(duration, f);
},
createPeriodicTimer: (Zone self, ZoneDelegate parent, Zone zone, Duration period, void Function(Timer timer) f) {
return Zone.root.createPeriodicTimer(period, f);
},
),
);
return realAsyncZone.run<Future<T?>>(() {
final Completer<T?> result = Completer<T?>();
_pendingAsyncTasks = Completer<void>();
try {
callback().then(result.complete).catchError(
(Object exception, StackTrace stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'Flutter test framework',
context: ErrorDescription('while running async test code'),
informationCollector: () {
return <DiagnosticsNode>[
ErrorHint('The exception was caught asynchronously.'),
];
},
));
result.complete(null);
},
);
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'Flutter test framework',
context: ErrorDescription('while running async test code'),
informationCollector: () {
return <DiagnosticsNode>[
ErrorHint('The exception was caught synchronously.'),
];
},
));
result.complete(null);
}
result.future.whenComplete(() {
_pendingAsyncTasks!.complete();
_pendingAsyncTasks = null;
});
return result.future;
});
}