5

I have a widget test similar to:

testWidgets('Widget test', (WidgetTester tester) async {
  provideMockedNetworkImages(() async {
    final widget = MyWidget();

    await WidgetTestFunctions.pumpWidgetTest(
      tester,
      widget,
    );

    // ....

    await tester.tap(find.byType(MyWidget));
    await tester.pump(new Duration(milliseconds: 3000));

    // ....

    expect(widget.value, myValue);
  });
});

And the following implementation of the on-tap method of the widget:

_onButtonPressed() async {      
  await animationController.forward();
  setState(() {
    // ...
    // Calls method that changes the widget value.
  });           
}

The problem that I have is that after calling the animationController.forward() method in the test the setState portion is not executed. How should I wait for this method to finish correctly? During the app runtime, this portion of the code is called correctly.

It seems like await tester.pump(new Duration(milliseconds: 3000)); is not working correctly, the animation has a duration of 1500 milliseconds and as you can see the pump duration is double.

Valentin Vignal
  • 6,151
  • 2
  • 33
  • 73
notarealgreal
  • 734
  • 16
  • 29

2 Answers2

2

Instead of await tester.pump(new Duration(milliseconds: 3000)); try await tester.pumpAndSettle();

this type of pump wait for the animations end and then pump the frames.

João Victor
  • 31
  • 1
  • 3
1

I had the same issue, and here is what was happening.

When you do

await animationController.forward();

You are not awaiting for a simple Future<void> to complete but a TickerFuture (extends Future<void>).

For some reason, in my tests, some of the TickerFutures from the animationController.forward() weere cancelled.

In the doc of the TickerProvider, it says:

If the Ticker is disposed without being stopped, or if it is stopped with canceled set to true, then this Future will never complete.

This class works like a normal Future, but has an additional property, orCancel, which returns a derivative Future that completes with an error if the Ticker that returned the TickerFuture was stopped with canceled set to true, or if it was disposed without being stopped.

To run a callback when either this future resolves or when the ticker is canceled, use whenCompleteOrCancel.

Now, the issue with whenCompleteOrCancel is that it returns void (and not Future<void> so we cannot wait for it.

So here is what I have done (inspired by the implementation of whenCompleteOrCancel):

Future<void> thunk(dynamic value) {
  return;
}
final TickerFuture ticker = animationController.forward();
await ticker.onCancel.then(thunk, onError: thunk); // <- This resolves even if the ticker is canceled and the tests are not stuck anymore.
Valentin Vignal
  • 6,151
  • 2
  • 33
  • 73