I ran into a similar issue where I needed a bunch of tests to run in sequence. I put together this little thing approximating semaphores using futures which worked for my use case, maybe it's useful for someone else too
You create a "sequence", and then you wrap the tests in runInSequence(...)
like this
void main() {
final seq = newTestSequence();
test('test 1', () async {
await runInSequence(seq, () async {
print('starting test 1...');
await Future.delayed(const Duration(milliseconds: 1000));
print('test 1 done');
});
});
test('test 2', () async {
await runInSequence(seq, () async {
print('starting test 2...');
await Future.delayed(const Duration(milliseconds: 10));
print('test 2 done');
});
});
}
This is the code for newSequence
and runInSequence
import 'dart:async';
import 'package:flutter/widgets.dart';
final Map<Key, Completer> _semaphores = {};
Key newTestSequence() {
final sequence = GlobalKey();
// create a new "semaphore" that will allow the first awaiter through
// immediately
_semaphores[sequence] = Completer();
_semaphores[sequence]!.complete();
return sequence;
}
Future<void> runInSequence(Key sequence, Future Function() test) async {
// block until resource is acquired
final c = await _claimSemaphore(sequence);
// execute test
await test();
// release resource
c.complete();
}
Future<Completer> _claimSemaphore(Key sequence) async {
if (!_semaphores.containsKey(sequence)) {
throw "unknown sequence $sequence; create one using `newTestSequence`";
}
final Completer c = _semaphores[sequence]!;
// block execution until the future is completed
await c.future;
// replace completer because futures can only be completed once
_semaphores[sequence] = Completer();
return _semaphores[sequence]!;
}