Add a timeout to pumpAndSettle. (#9195)

This commit is contained in:
Ian Hickson 2017-04-05 12:27:42 -07:00 committed by GitHub
parent 86a490ffe8
commit e355c60124
3 changed files with 51 additions and 5 deletions

View File

@ -141,6 +141,16 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
/// The default test timeout for tests when using this binding. /// The default test timeout for tests when using this binding.
test_package.Timeout get defaultTestTimeout; 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), /// Triggers a frame sequence (build/layout/paint/etc),
/// then flushes microtasks. /// then flushes microtasks.
/// ///
@ -466,6 +476,9 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
} }
FakeAsync _fakeAsync; FakeAsync _fakeAsync;
@override
Clock get clock => _clock;
Clock _clock; Clock _clock;
@override @override
@ -490,7 +503,7 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
_phase = newPhase; _phase = newPhase;
if (hasScheduledFrame) { if (hasScheduledFrame) {
handleBeginFrame(new Duration( handleBeginFrame(new Duration(
milliseconds: _clock.now().millisecondsSinceEpoch milliseconds: _clock.now().millisecondsSinceEpoch,
)); ));
} }
_fakeAsync.flushMicrotasks(); _fakeAsync.flushMicrotasks();
@ -615,6 +628,9 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
bool get inTest => _inTest; bool get inTest => _inTest;
bool _inTest = false; bool _inTest = false;
@override
Clock get clock => const Clock();
@override @override
int get microtaskCount { int get microtaskCount {
// Unsupported until we have a wrapper around the real async API // Unsupported until we have a wrapper around the real async API

View File

@ -198,9 +198,13 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
/// ///
/// This essentially waits for all animations to have completed. /// This essentially waits for all animations to have completed.
/// ///
/// This function will never return (and the test will hang and eventually /// If it takes longer that the given `timeout` to settle, then the test will
/// time out and fail) if there is an infinite animation in progress (for /// fail (this method will throw an exception). In particular, this means that
/// example, if there is an indeterminate progress indicator spinning). /// 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. /// 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. /// matches the expected number of pumps.
Future<int> pumpAndSettle([ Future<int> pumpAndSettle([
Duration duration = const Duration(milliseconds: 100), 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 != null);
assert(duration > Duration.ZERO); assert(duration > Duration.ZERO);
assert(timeout != null);
assert(timeout > Duration.ZERO);
int count = 0; int count = 0;
return TestAsyncUtils.guard(() async { return TestAsyncUtils.guard(() async {
final DateTime endTime = binding.clock.fromNowBy(timeout);
do { do {
if (binding.clock.now().isAfter(endTime))
throw new FlutterError('pumpAndSettle timed out');
await binding.pump(duration, phase); await binding.pump(duration, phase);
count += 1; count += 1;
} while (hasRunningAnimations); } while (hasRunningAnimations);

View File

@ -201,4 +201,24 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(tester.hasRunningAnimations, isFalse); 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
});
} }