What’s a future

It’s basically an asynchronous operation, you could set a callback for when the operation finishes or when an error occurs.

Completer

When testing you might have to call multiple asynchronous operations and wait for their succession.

And to do that, you need Completer. You can chain multiple futures inside each other and assign Completer to an error if an error occurs.

Consider the following snippet:

final com = Completer();
couldFail1.then((val) {
	couldFail2.then((val) {
		couldFail3.then((val){
			com.complete(); // successful
		}).catchError((e) {
			com.completeError(e);
		});
	}).catchError((e) {
		com.completeError(e);
	});
}).catchError((e) {
	com.completeError(e);
});

Then to ensure that no error passes, use the completes match.

// include the snippet above for this to work
expect(com, completes);
// or
expect(com, completion(null));

As a bonus, in-case you want the operation to be synchronous - you could wrap the operation around a function and do a while loop like so.

void doAsyncSynchronously() {
	final com = Completer();
	couldFail1.then((val) {
		couldFail2.then((val) {
			couldFail3.then((val){
				com.complete(); // successful
			}).catchError((e) {
				com.completeError(e);
			});
		}).catchError((e) {
			com.completeError(e);
		});
	}).catchError((e) {
		com.completeError(e);
	});

	// this forces the function to wait
	while(!com.isCompleted) {}

	return; // not neccesary
}