svprdga
svprdga

Reputation: 2549

Widget test a widget which uses WidgetsBinding.instance.addPostFrameCallback()

I'm trying to do a widget test in flutter to one widget which uses WidgetsBinding.instance.addPostFrameCallback() to show a dialog at the very beggining of the widget lifecycle.

The widget works fine, but I cannot figure out how to do a widget test, because the very first expect() of the test is executed before this post frame is triggered.

Anyway to "tell" the test to wait until all the post frames are dispatched?

PD: tester.pump(), tester.pumpAndSettle(), etc. are not working.

Upvotes: 12

Views: 5055

Answers (3)

Andrei Lesnitsky
Andrei Lesnitsky

Reputation: 1088

To schedule a frame (and force postFrameCallback to be called) in flutter test environment you need to call tester.binding.scheduleFrame() before tester.pump().

Alternatively, if you don't care about the whole widget tree being rebuilt, you could call tester.pumpWidget(widget) instead of tester.pump()

Example test:

testWidgets('testing frames', (tester) async {
  final w = Container();
  int framesCount = 0;

  tester.binding.addPersistentFrameCallback((timeStamp) {
    framesCount++;
  });

  await tester.pumpWidget(w);
  expect(framesCount, equals(1));

  // pumpWidget calls [scheduleFrame]
  await tester.pumpWidget(w);
  expect(framesCount, equals(2));

  await tester.pump();
  // no frame was scheduled, so framesCount is still 2
  expect(framesCount, equals(2));

  tester.binding.scheduleFrame(); // --
  await tester.pump();            //   |
  expect(framesCount, equals(3)); // <-

  // pumpWidget calls [scheduleFrame]
  await tester.pumpWidget(w);
  expect(framesCount, equals(4));
});

Upvotes: 6

chess0045
chess0045

Reputation: 21

This worked for me:

// press button
await tester.tap(find.text("Save"));
// await the flushbar or snackbar to appear
await tester.pumpAndSettle(const Duration(seconds: 1));
// find by text or key
expect(find.text("Error saving note"), findsOneWidget);
// this prevents this error:
// A Timer is still pending even after the widget tree was disposed.
// the flushbar in my code is displayed for 5 seconds. So we wait for it to 
// go away.
await tester.pumpAndSettle(const Duration(seconds: 5));

I dont know if this is the proper way to do. But it works. Good luck!

Upvotes: 2

christianalfoni
christianalfoni

Reputation: 1034

But what do you know... suddenly it popped up:

    tester.binding.scheduleWarmUpFrame();

Run that :-)

Taken from here: https://chromium.googlesource.com/external/github.com/flutter/flutter/+/v0.9.2/packages/flutter/test/widgets/binding_test.dart

Upvotes: 10

Related Questions