pumpAndSettle method

Future<int> pumpAndSettle ([Duration duration = const Duration(milliseconds: 100), EnginePhase phase = EnginePhase.sendSemanticsUpdate, Duration timeout = const Duration(minutes: 10) ])

Repeatedly calls pump with the given duration until there are no longer any frames scheduled. This will call pump at least once, even if no frames are scheduled when the function is called, to flush any pending microtasks which may themselves schedule a frame.

This essentially waits for all animations to have completed.

If it takes longer that the given timeout to settle, then the test will fail (this method will throw an exception). In particular, this means that if there is an infinite animation in progress (for example, if there is an indeterminate progress indicator spinning), this method will throw.

The default timeout is ten minutes, which is longer than most reasonable finite animations would last.

If the function returns, it returns the number of pumps that it performed.

In general, it is better practice to figure out exactly why each frame is needed, and then to pump exactly as many frames as necessary. This will help catch regressions where, for instance, an animation is being started one frame later than it should.

Alternatively, one can check that the return value from this function matches the expected number of pumps.

Implementation

Future<int> pumpAndSettle([
  Duration duration = const Duration(milliseconds: 100),
  EnginePhase phase = EnginePhase.sendSemanticsUpdate,
  Duration timeout = const Duration(minutes: 10),
]) {
  assert(duration != null);
  assert(duration > Duration.zero);
  assert(timeout != null);
  assert(timeout > Duration.zero);
  assert(() {
    final WidgetsBinding binding = this.binding;
    if (binding is LiveTestWidgetsFlutterBinding &&
        binding.framePolicy == LiveTestWidgetsFlutterBindingFramePolicy.benchmark) {
      throw 'When using LiveTestWidgetsFlutterBindingFramePolicy.benchmark, '
            'hasScheduledFrame is never set to true. This means that pumpAndSettle() '
            'cannot be used, because it has no way to know if the application has '
            'stopped registering new frames.';
    }
    return true;
  }());
  int count = 0;
  return TestAsyncUtils.guard<void>(() async {
    final DateTime endTime = binding.clock.fromNowBy(timeout);
    do {
      if (binding.clock.now().isAfter(endTime))
        throw FlutterError('pumpAndSettle timed out');
      await binding.pump(duration, phase);
      count += 1;
    } while (binding.hasScheduledFrame);
  }).then<int>((_) => count);
}