Commit 8a186f3b authored by Dan Rubel's avatar Dan Rubel Committed by GitHub

tests to assert futures complete as expected (#5947)

parent 74f50bfb
......@@ -154,6 +154,8 @@ class AnimationController extends Animation<double>
AnimationStatus _status;
/// Starts running this animation forwards (towards the end).
///
/// Returns a [Future] that completes when the animation is complete.
Future<Null> forward({ double from }) {
_direction = _AnimationDirection.forward;
if (from != null)
......@@ -162,6 +164,8 @@ class AnimationController extends Animation<double>
}
/// Starts running this animation in reverse (towards the beginning).
///
/// Returns a [Future] that completes when the animation is complete.
Future<Null> reverse({ double from }) {
_direction = _AnimationDirection.reverse;
if (from != null)
......@@ -170,6 +174,8 @@ class AnimationController extends Animation<double>
}
/// Drives the animation from its current value to target.
///
/// Returns a [Future] that completes when the animation is complete.
Future<Null> animateTo(double target, { Duration duration, Curve curve: Curves.linear }) {
Duration simulationDuration = duration;
if (simulationDuration == null) {
......
......@@ -472,6 +472,8 @@ class ScrollableState<T extends Scrollable> extends State<T> {
/// This function does not accept a zero duration. To jump-scroll to
/// the new offset, do not provide a duration, rather than providing
/// a zero duration.
///
/// The returned [Future] completes when the scrolling animation is complete.
Future<Null> scrollTo(double newScrollOffset, {
Duration duration,
Curve curve: Curves.ease,
......@@ -550,6 +552,8 @@ class ScrollableState<T extends Scrollable> extends State<T> {
/// Calling this function starts a physics-based animation of the scroll
/// offset with the given value as the initial velocity. The physics
/// simulation is determined by the scroll behavior.
///
/// The returned [Future] completes when the scrolling animation is complete.
Future<Null> fling(double scrollVelocity) {
if (scrollVelocity.abs() > kPixelScrollTolerance.velocity)
return _startToEndAnimation(scrollVelocity);
......
......@@ -9,7 +9,6 @@ import 'package:flutter/widgets.dart';
void main() {
testWidgets('Verify that a tap dismisses a modal BottomSheet', (WidgetTester tester) async {
BuildContext savedContext;
bool showBottomSheetThenCalled = false;
await tester.pumpWidget(new MaterialApp(
home: new Builder(
......@@ -23,6 +22,7 @@ void main() {
await tester.pump();
expect(find.text('BottomSheet'), findsNothing);
bool showBottomSheetThenCalled = false;
showModalBottomSheet/*<Null>*/(
context: savedContext,
builder: (BuildContext context) => new Text('BottomSheet')
......@@ -44,14 +44,23 @@ void main() {
await tester.pump(new Duration(seconds: 1)); // frame after the animation (sheet has been removed)
expect(find.text('BottomSheet'), findsNothing);
showModalBottomSheet/*<Null>*/(context: savedContext, builder: (BuildContext context) => new Text('BottomSheet'));
showBottomSheetThenCalled = false;
showModalBottomSheet/*<Null>*/(
context: savedContext,
builder: (BuildContext context) => new Text('BottomSheet'),
).then((Null result) {
expectSync(result, isNull);
showBottomSheetThenCalled = true;
});
await tester.pump(); // bottom sheet show animation starts
await tester.pump(new Duration(seconds: 1)); // animation done
expect(find.text('BottomSheet'), findsOneWidget);
expect(showBottomSheetThenCalled, isFalse);
// Tap above the the bottom sheet to dismiss it
await tester.tapAt(new Point(20.0, 20.0));
await tester.pump(); // bottom sheet dismiss animation starts
expect(showBottomSheetThenCalled, isTrue);
await tester.pump(new Duration(seconds: 1)); // animation done
await tester.pump(new Duration(seconds: 1)); // rebuild frame
expect(find.text('BottomSheet'), findsNothing);
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
......@@ -53,22 +55,31 @@ void main() {
)
); // t=0
recordMetrics();
controller.forward();
Completer<Null> completer = new Completer<Null>();
controller.forward().whenComplete(completer.complete);
expect(completer.isCompleted, isFalse);
await tester.pump(); // t=0 again
expect(completer.isCompleted, isFalse);
recordMetrics();
await tester.pump(const Duration(seconds: 1)); // t=1
expect(completer.isCompleted, isFalse);
recordMetrics();
await tester.pump(const Duration(seconds: 1)); // t=2
expect(completer.isCompleted, isFalse);
recordMetrics();
await tester.pump(const Duration(seconds: 3)); // t=5
expect(completer.isCompleted, isFalse);
recordMetrics();
await tester.pump(const Duration(seconds: 5)); // t=10
expect(completer.isCompleted, isFalse);
recordMetrics();
expect(sizes, equals(<Size>[const Size(10.0, 10.0), const Size(10.0, 10.0), const Size(10.0, 10.0), const Size(10.0, 10.0), const Size(10.0, 10.0), const Size(10.0, 10.0)]));
expect(positions, equals(<Offset>[const Offset(10.0, 10.0), const Offset(10.0, 10.0), const Offset(17.0, 17.0), const Offset(24.0, 24.0), const Offset(45.0, 45.0), const Offset(80.0, 80.0)]));
controller.stop();
await tester.pump();
expect(completer.isCompleted, isTrue);
});
}
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
......@@ -57,8 +59,11 @@ Future<Null> performTest(WidgetTester tester, bool maintainState) async {
expect(find.text('10'), findsNothing);
expect(find.text('100'), findsNothing);
tester.state/*<ScrollableState>*/(find.byType(Scrollable)).scrollTo(1000.0);
Completer<Null> completer = new Completer<Null>();
tester.state/*<ScrollableState>*/(find.byType(Scrollable)).scrollTo(1000.0).whenComplete(completer.complete);
expect(completer.isCompleted, isFalse);
await tester.pump(new Duration(seconds: 1));
expect(completer.isCompleted, isTrue);
// we're 600 pixels high, each item is 100 pixels high, scroll position is
// 1000, so we should have exactly 6 items, 10..15.
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart';
......@@ -22,6 +24,14 @@ Widget _buildScroller({Key key, List<String> log}) {
}
void main() {
GlobalKey<ScrollableState<Scrollable>> scrollKey;
Completer<Null> scrollTo(double newScrollOffset, { Duration duration }) {
Completer<Null> completer = new Completer<Null>();
scrollKey.currentState.scrollTo(newScrollOffset, duration: duration).whenComplete(completer.complete);
return completer;
}
testWidgets('Scroll event drag', (WidgetTester tester) async {
List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(log: log));
......@@ -42,12 +52,13 @@ void main() {
});
testWidgets('Scroll scrollTo animation', (WidgetTester tester) async {
GlobalKey<ScrollableState<Scrollable>> scrollKey = new GlobalKey<ScrollableState<Scrollable>>();
scrollKey = new GlobalKey<ScrollableState<Scrollable>>();
List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(key: scrollKey, log: log));
expect(log, equals(<String>[]));
scrollKey.currentState.scrollTo(100.0, duration: const Duration(seconds: 1));
Completer<Null> completer = scrollTo(100.0, duration: const Duration(seconds: 1));
expect(completer.isCompleted, isFalse);
expect(log, equals(<String>['scrollstart']));
await tester.pump(const Duration(milliseconds: 100));
expect(log, equals(<String>['scrollstart']));
......@@ -55,60 +66,74 @@ void main() {
expect(log, equals(<String>['scrollstart', 'scroll']));
await tester.pump(const Duration(milliseconds: 1500));
expect(log, equals(<String>['scrollstart', 'scroll', 'scroll', 'scrollend']));
expect(completer.isCompleted, isTrue);
});
testWidgets('Scroll scrollTo no animation', (WidgetTester tester) async {
GlobalKey<ScrollableState<Scrollable>> scrollKey = new GlobalKey<ScrollableState<Scrollable>>();
scrollKey = new GlobalKey<ScrollableState<Scrollable>>();
List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(key: scrollKey, log: log));
expect(log, equals(<String>[]));
scrollKey.currentState.scrollTo(100.0);
Completer<Null> completer = scrollTo(100.0);
expect(completer.isCompleted, isFalse);
expect(log, equals(<String>['scrollstart', 'scroll', 'scrollend']));
await tester.pump();
expect(completer.isCompleted, isTrue);
});
testWidgets('Scroll during animation', (WidgetTester tester) async {
GlobalKey<ScrollableState<Scrollable>> scrollKey = new GlobalKey<ScrollableState<Scrollable>>();
scrollKey = new GlobalKey<ScrollableState<Scrollable>>();
List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(key: scrollKey, log: log));
expect(log, equals(<String>[]));
scrollKey.currentState.scrollTo(100.0, duration: const Duration(seconds: 1));
Completer<Null> completer = scrollTo(100.0, duration: const Duration(seconds: 1));
expect(completer.isCompleted, isFalse);
expect(log, equals(<String>['scrollstart']));
await tester.pump(const Duration(milliseconds: 100));
expect(log, equals(<String>['scrollstart']));
await tester.pump(const Duration(milliseconds: 100));
expect(log, equals(<String>['scrollstart', 'scroll']));
scrollKey.currentState.scrollTo(100.0);
expect(completer.isCompleted, isFalse);
completer = scrollTo(100.0);
expect(completer.isCompleted, isFalse);
expect(log, equals(<String>['scrollstart', 'scroll', 'scroll']));
await tester.pump(const Duration(milliseconds: 100));
expect(log, equals(<String>['scrollstart', 'scroll', 'scroll', 'scrollend']));
await tester.pump(const Duration(milliseconds: 1500));
expect(log, equals(<String>['scrollstart', 'scroll', 'scroll', 'scrollend']));
expect(completer.isCompleted, isTrue);
});
testWidgets('Scroll during animation', (WidgetTester tester) async {
GlobalKey<ScrollableState<Scrollable>> scrollKey = new GlobalKey<ScrollableState<Scrollable>>();
scrollKey = new GlobalKey<ScrollableState<Scrollable>>();
List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(key: scrollKey, log: log));
expect(log, equals(<String>[]));
scrollKey.currentState.scrollTo(100.0, duration: const Duration(seconds: 1));
Completer<Null> completer = scrollTo(100.0, duration: const Duration(seconds: 1));
expect(completer.isCompleted, isFalse);
expect(log, equals(<String>['scrollstart']));
await tester.pump(const Duration(milliseconds: 100));
expect(log, equals(<String>['scrollstart']));
await tester.pump(const Duration(milliseconds: 100));
expect(log, equals(<String>['scrollstart', 'scroll']));
scrollKey.currentState.scrollTo(100.0, duration: const Duration(seconds: 1));
expect(completer.isCompleted, isFalse);
completer = scrollTo(100.0, duration: const Duration(seconds: 1));
expect(completer.isCompleted, isFalse);
expect(log, equals(<String>['scrollstart', 'scroll']));
await tester.pump(const Duration(milliseconds: 100));
expect(log, equals(<String>['scrollstart', 'scroll']));
await tester.pump(const Duration(milliseconds: 1500));
expect(log, equals(<String>['scrollstart', 'scroll', 'scroll', 'scrollend']));
expect(completer.isCompleted, isTrue);
});
testWidgets('fling, fling generates two start/end pairs', (WidgetTester tester) async {
GlobalKey<ScrollableState<Scrollable>> scrollKey = new GlobalKey<ScrollableState<Scrollable>>();
scrollKey = new GlobalKey<ScrollableState<Scrollable>>();
List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(key: scrollKey, log: log));
......@@ -127,7 +152,7 @@ void main() {
});
testWidgets('fling up ends', (WidgetTester tester) async {
GlobalKey<ScrollableState<Scrollable>> scrollKey = new GlobalKey<ScrollableState<Scrollable>>();
scrollKey = new GlobalKey<ScrollableState<Scrollable>>();
List<String> log = <String>[];
await tester.pumpWidget(_buildScroller(key: scrollKey, log: log));
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart';
......@@ -85,6 +87,11 @@ void main() {
),
right: new Text('Not Today')
);
Completer<Null> scrollTo(double newScrollOffset) {
Completer<Null> completer = new Completer<Null>();
scrollableKey.currentState.scrollTo(newScrollOffset).whenComplete(completer.complete);
return completer;
}
await tester.pumpWidget(testWidget);
......@@ -92,12 +99,14 @@ void main() {
callbackTracker.clear();
scrollableKey.currentState.scrollTo(400.0);
Completer<Null> completer = scrollTo(400.0);
expect(completer.isCompleted, isFalse);
// now only 3 should fit, numbered 2-4.
await tester.pumpWidget(testWidget);
expect(callbackTracker, equals(<int>[2, 3, 4]));
expect(completer.isCompleted, isTrue);
callbackTracker.clear();
});
......@@ -134,6 +143,11 @@ void main() {
),
right: new Text('Not Today')
);
Completer<Null> scrollTo(double newScrollOffset) {
Completer<Null> completer = new Completer<Null>();
scrollableKey.currentState.scrollTo(newScrollOffset).whenComplete(completer.complete);
return completer;
}
await tester.pumpWidget(testWidget);
......@@ -141,12 +155,14 @@ void main() {
callbackTracker.clear();
scrollableKey.currentState.scrollTo(400.0);
Completer<Null> completer = scrollTo(400.0);
expect(completer.isCompleted, isFalse);
// now only 4 should fit, numbered 2-5.
await tester.pumpWidget(testWidget);
expect(callbackTracker, equals(<int>[2, 3, 4, 5]));
expect(completer.isCompleted, isTrue);
callbackTracker.clear();
});
......@@ -174,24 +190,35 @@ void main() {
itemExtent: 300.0,
itemCount: 10
);
Completer<Null> scrollTo(double newScrollOffset) {
Completer<Null> completer = new Completer<Null>();
scrollableKey.currentState.scrollTo(newScrollOffset).whenComplete(completer.complete);
return completer;
}
await tester.pumpWidget(testWidget);
expect(callbackTracker, equals(<int>[0, 1]));
callbackTracker.clear();
scrollableKey.currentState.scrollTo(150.0);
Completer<Null> completer = scrollTo(150.0);
expect(completer.isCompleted, isFalse);
await tester.pumpWidget(testWidget);
expect(callbackTracker, equals(<int>[0, 1, 2]));
expect(completer.isCompleted, isTrue);
callbackTracker.clear();
scrollableKey.currentState.scrollTo(600.0);
completer = scrollTo(600.0);
expect(completer.isCompleted, isFalse);
await tester.pumpWidget(testWidget);
expect(callbackTracker, equals(<int>[2, 3]));
expect(completer.isCompleted, isTrue);
callbackTracker.clear();
scrollableKey.currentState.scrollTo(750.0);
completer = scrollTo(750.0);
expect(completer.isCompleted, isFalse);
await tester.pumpWidget(testWidget);
expect(callbackTracker, equals(<int>[2, 3, 4]));
expect(completer.isCompleted, isTrue);
callbackTracker.clear();
});
......
......@@ -46,8 +46,10 @@ set scrollOffset(double value) {
scrollableState.scrollTo(value);
}
Future<Null> fling(double velocity) {
return scrollableState.fling(velocity);
Completer<Null> fling(double velocity) {
Completer<Null> completer = new Completer<Null>();
scrollableState.fling(velocity).whenComplete(completer.complete);
return completer;
}
void main() {
......@@ -60,49 +62,55 @@ void main() {
Duration dt = const Duration(seconds: 2);
fling(1000.0);
Completer<Null> completer = fling(1000.0);
expect(completer.isCompleted, isFalse);
await tester.pump(); // Start the scheduler at 0.0
await tester.pump(dt);
expect(scrollOffset, closeTo(200.0, 1.0));
expect(completer.isCompleted, isTrue);
scrollOffset = 0.0;
await tester.pump();
expect(scrollOffset, 0.0);
fling(2000.0);
completer = fling(2000.0);
expect(completer.isCompleted, isFalse);
await tester.pump();
await tester.pump(dt);
expect(scrollOffset, closeTo(400.0, 1.0));
expect(completer.isCompleted, isTrue);
scrollOffset = 400.0;
await tester.pump();
expect(scrollOffset, 400.0);
fling(-800.0);
completer = fling(-800.0);
expect(completer.isCompleted, isFalse);
await tester.pump();
await tester.pump(dt);
expect(scrollOffset, closeTo(0.0, 1.0));
expect(completer.isCompleted, isTrue);
scrollOffset = 800.0;
await tester.pump();
expect(scrollOffset, 800.0);
fling(-2000.0);
completer = fling(-2000.0);
expect(completer.isCompleted, isFalse);
await tester.pump();
await tester.pump(dt);
expect(scrollOffset, closeTo(200.0, 1.0));
expect(completer.isCompleted, isTrue);
scrollOffset = 800.0;
await tester.pump();
expect(scrollOffset, 800.0);
bool completed = false;
fling(-2000.0).then((_) {
completed = true;
expectSync(scrollOffset, closeTo(200.0, 1.0));
});
completer = fling(-2000.0);
expect(completer.isCompleted, isFalse);
await tester.pump();
await tester.pump(dt);
expect(completed, true);
expect(completer.isCompleted, isTrue);
expectSync(scrollOffset, closeTo(200.0, 1.0));
});
}
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