Commit e355c601 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Add a timeout to pumpAndSettle. (#9195)

parent 86a490ff
......@@ -141,6 +141,16 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
/// The default test timeout for tests when using this binding.
test_package.Timeout get defaultTestTimeout;
/// The current time.
///
/// In the automated test environment (`flutter test`), this is a fake clock
/// that begins in January 2015 at the start of the test and advances each
/// time [pump] is called with a non-zero duration.
///
/// In the live testing environment (`flutter run`), this object shows the
/// actual current wall-clock time.
Clock get clock;
/// Triggers a frame sequence (build/layout/paint/etc),
/// then flushes microtasks.
///
......@@ -466,6 +476,9 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
}
FakeAsync _fakeAsync;
@override
Clock get clock => _clock;
Clock _clock;
@override
......@@ -490,7 +503,7 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
_phase = newPhase;
if (hasScheduledFrame) {
handleBeginFrame(new Duration(
milliseconds: _clock.now().millisecondsSinceEpoch
milliseconds: _clock.now().millisecondsSinceEpoch,
));
}
_fakeAsync.flushMicrotasks();
......@@ -615,6 +628,9 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
bool get inTest => _inTest;
bool _inTest = false;
@override
Clock get clock => const Clock();
@override
int get microtaskCount {
// Unsupported until we have a wrapper around the real async API
......
......@@ -198,9 +198,13 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
///
/// This essentially waits for all animations to have completed.
///
/// This function will never return (and the test will hang and eventually
/// time out and fail) if there is an infinite animation in progress (for
/// example, if there is an indeterminate progress indicator spinning).
/// 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.
///
......@@ -213,13 +217,19 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
/// matches the expected number of pumps.
Future<int> pumpAndSettle([
Duration duration = const Duration(milliseconds: 100),
EnginePhase phase = EnginePhase.sendSemanticsTree
EnginePhase phase = EnginePhase.sendSemanticsTree,
Duration timeout = const Duration(minutes: 10),
]) {
assert(duration != null);
assert(duration > Duration.ZERO);
assert(timeout != null);
assert(timeout > Duration.ZERO);
int count = 0;
return TestAsyncUtils.guard(() async {
final DateTime endTime = binding.clock.fromNowBy(timeout);
do {
if (binding.clock.now().isAfter(endTime))
throw new FlutterError('pumpAndSettle timed out');
await binding.pump(duration, phase);
count += 1;
} while (hasRunningAnimations);
......
......@@ -201,4 +201,24 @@ void main() {
await tester.pumpAndSettle();
expect(tester.hasRunningAnimations, isFalse);
});
testWidgets('pumpAndSettle control test', (WidgetTester tester) async {
final AnimationController controller = new AnimationController(
duration: const Duration(minutes: 525600),
vsync: const TestVSync()
);
expect(await tester.pumpAndSettle(), 1);
controller.forward();
try {
await tester.pumpAndSettle();
expect(true, isFalse);
} catch (e) {
expect(e, isFlutterError);
}
controller.stop();
expect(await tester.pumpAndSettle(), 1);
controller.duration = const Duration(seconds: 1);
controller.forward();
expect(await tester.pumpAndSettle(const Duration(milliseconds: 300)), 5); // 0, 300, 600, 900, 1200ms
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment