Writing asynchronous tests with streams can be a challenge.

And if we’re not careful, we can end up with a test that “hangs” while waiting for stream values to be emitted.

Here’s an example:

test(
  'test timeout',
  () async {
    final controller = StreamController<int>();
    // add some values (without closing the controller)
    controller.addStream(Stream.fromIterable([1, 2, 3]));
    await expectLater(
      controller.stream,
      emitsInOrder([1, 2, 3, 4]),
    );
  },
);

The test above will wait and eventually timeout because the stream never emits the last expected value.

TimeoutException after 0:00:30.000000: Test timed out after 30 seconds.

And if we have hundreds or thousands of tests running on CI, a default timeout of 30 seconds can cost us a lot of time and money. 💰

Setting a Custom Timeout

To work around this, we can add a timeout argument:

test(
  'test timeout',
  () async {
    final controller = StreamController<int>();
    // add some values (without closing the controller)
    controller.addStream(Stream.fromIterable([1, 2, 3]));
    await expectLater(
      controller.stream,
      emitsInOrder([1, 2, 3, 4]),
    );
  },
  // 30 seconds is too long. This is much better:
  timeout: const Timeout(Duration(seconds: 1)),
);

In this case, the test will still fail, but it will do so after 1 second.

The @Timeout annotation

But of we have a lot of tests, setting an individual timeout for each test is quite tedious.

Instead, we can define a @Timeout annotation that will apply to all the tests in the file:

// Note: this has to be on the very first line:
@Timeout(Duration(seconds: 1))
import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
 
void main() {
  test(
    'test timeout',
    () async {
      final controller = StreamController<int>();
      // add some values (without closing the controller)
      controller.addStream(Stream.fromIterable([1, 2, 3]));
      await expectLater(
        controller.stream,
        emitsInOrder([1, 2, 3, 4]),
      );
    },
  );
}

For more info, read the documentation of the official Dart test package:

Happy coding!

Flutter Foundations Course Now Available

I launched a brand new course that covers testing in great depth, along with other important topics like app architecture, state management, navigation & routing, and much more: