Why does WidgetTester.pump not work for navigation changes where WidgetTester.pumpAndSettle does?

2,067 views
Skip to first unread message

Kent Boogaart

unread,
Apr 18, 2018, 6:32:06 PM4/18/18
to Flutter Dev
Hi,

I'm writing some widget tests. In one particular test, I possibly nav from one page to the next when the user taps something (the same test code is checking two different scenarios - one where nav is expected, one where it isn't). The current page has an infinite animation, so I can't use pumpAndSettle after performing the tap, because if no nav occurs then it will just time out. And I can't just call pump without a small duration because navigation takes time. However, I thought calling pump with a reasonable duration (e.g. 3 seconds) would work, but it doesn't. Even if I set it to an hour, it doesn't.

I have repro'd this as follows:

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new Page1(),
);
}
}

class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
var body = new Column(
children: <Widget>[
const Text("The first page"),
new MaterialButton(child: const Text("NAVIGATE"), onPressed: () => Navigator.of(context).push(new MaterialPageRoute(builder: (_) => new Page2()))),
],
);

var scaffold = new Scaffold(
body: body,
appBar: new AppBar(title: const Text("Page 1")),
);

return scaffold;
}
}

class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
var body = const Text("The second page");

var scaffold = new Scaffold(
body: body,
appBar: new AppBar(title: const Text("Page 2")),
);

return scaffold;
}
}


import 'package:flutter_test/flutter_test.dart';
import 'package:repro_nav_widget_test/main.dart';

void main() {
testWidgets('repro', (WidgetTester tester) async {
await tester.pumpWidget(new MyApp());

expect(find.text("Page 1"), findsOneWidget);

await tester.tap(find.text("NAVIGATE"));

// THIS WORKS
//await tester.pumpAndSettle();

// THIS DOES NOT
await tester.pump(const Duration(seconds: 3));

expect(find.text("Page 2"), findsOneWidget);
});
}

Can anyone tell me why pumpAndSettle works where pump(Duration(seconds: 3)) does not?

Thanks,
Kent

Ian Hickson

unread,
Apr 20, 2018, 12:02:52 PM4/20/18
to Kent Boogaart, Flutter Dev
"pump" works by running one frame, pretending that there was the given duration of jank before the frame.

For a navigation, you need to pump two frames: the first is to begin showing everything, the second is to finish the animations and get everything into its final place.

So generally, you want to do something like:

    await tester.pump();
    await tester.pump(const Duration(seconds: 3));

This is actually the preferred pattern in general; pumpAndSettle is something I would generally discourage from use except when you specifically need it. Mostly it's useful as a way to count the number of frames that were required, to verify that there weren't excessive frames pumped.


--
You received this message because you are subscribed to the Google Groups "Flutter Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to flutter-dev...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--

--
Ian Hickson

😸
Reply all
Reply to author
Forward
0 new messages