Unverified Commit a36b0ba4 authored by Ming Lyu (CareF)'s avatar Ming Lyu (CareF) Committed by GitHub

promote WidgetTester pumpAndSettle (#62640)

parent e03980ec
......@@ -440,6 +440,34 @@ abstract class WidgetController {
/// be appropriate to return in the implementation of this method.
Future<void> pump([Duration duration]);
/// 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.
Future<int> pumpAndSettle([
Duration duration = const Duration(milliseconds: 100),
]);
/// Attempts to drag the given widget by the given offset, by
/// starting a drag in the middle of the widget.
///
......@@ -908,6 +936,22 @@ class LiveWidgetController extends WidgetController {
await binding.endOfFrame;
}
@override
Future<int> pumpAndSettle([
Duration duration = const Duration(milliseconds: 100),
]) {
assert(duration != null);
assert(duration > Duration.zero);
return TestAsyncUtils.guard<int>(() async {
int count = 0;
do {
await pump(duration);
count += 1;
} while (binding.hasScheduledFrame);
return count;
});
}
@override
Future<List<Duration>> handlePointerEventRecord(List<PointerEventRecord> records) {
assert(records != null);
......
......@@ -604,39 +604,13 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
}
}
/// 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.
@override
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 &&
......@@ -648,16 +622,14 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
}
return true;
}());
int count = 0;
return TestAsyncUtils.guard<void>(() async {
final DateTime endTime = binding.clock.fromNowBy(timeout);
return TestAsyncUtils.guard<int>(() async {
int count = 0;
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);
return count;
});
}
/// Repeatedly pump frames that render the `target` widget with a fixed time
......
......@@ -29,6 +29,39 @@ class _CountButtonState extends State<CountButton> {
}
}
class AnimateSample extends StatefulWidget {
@override
_AnimateSampleState createState() => _AnimateSampleState();
}
class _AnimateSampleState extends State<AnimateSample>
with SingleTickerProviderStateMixin {
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
)..forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, _) => Text('Value: ${_controller.value}'),
);
}
}
void main() {
test('Test pump on LiveWidgetController', () async {
runApp(MaterialApp(home: Center(child: CountButton())));
......@@ -44,6 +77,16 @@ void main() {
expect(find.text('Counter 1'), findsOneWidget);
});
test('Test pumpAndSettle on LiveWidgetController', () async {
runApp(MaterialApp(home: Center(child: AnimateSample())));
await SchedulerBinding.instance.endOfFrame;
final WidgetController controller =
LiveWidgetController(WidgetsBinding.instance);
expect(find.text('Value: 1.0'), findsNothing);
await controller.pumpAndSettle();
expect(find.text('Value: 1.0'), findsOneWidget);
});
test('Input event array on LiveWidgetController', () async {
final List<String> logs = <String>[];
runApp(
......
......@@ -465,21 +465,11 @@ void main() {
testWidgets('pumpAndSettle control test', (WidgetTester tester) async {
final AnimationController controller = AnimationController(
duration: const Duration(minutes: 525600),
duration: const Duration(seconds: 1),
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