runAsync<T> method
tester.runAsync with a watchdog on it: real async work, and a sentence
rather than a hang when it turns out not to be work at all.
Everything a scenario waits on for real — a database, a socket, an http call, an asset the app has not read yet — needs a turn of the real event loop, and this is the turn. The catch is that no pump can run while it is open, so awaiting a future that was made outside it, and that only a pump could complete, deadlocks the whole run silently. The watchdog reports that within seconds, and names the cache usually behind it.
var bytes = await s.runAsync(() => report.generatePdf());
A verb like the rest of them: it settles afterwards and captures what
landed. Real work arriving is exactly the moment the tree has something
new to paint — a query returns and the list fills in — and before this
it was the one method on this surface that sat among tap and drag
and quietly did neither, so every site that needed the repaint settled
by hand.
Work that lands nothing on screen still takes no step: the automatic
shot is skipped where the settle drew no frame, so the generatePdf
above is followed by its document and by nothing else.
Implementation
Future<T?> runAsync<T>(
Future<T> Function() callback, {
Shot? shot,
Settle? settle,
}) => _step(
shot,
settle,
() => watchRunAsync(() => tester.runAsync(callback)),
verb: 'runAsync',
autoShotNeedsChange: true,
);