Little Monkey
Little Monkey

Reputation: 6157

Flutter: how to test the scroll

I have a ListView.builder with a ScrollController as controller:

  _buildListView(state) => ListView.builder(
        itemBuilder: (_, int index) => _draw(index, state),
        itemCount: state.count
        controller: _scrollController,
      );

I add a listener to the controller:

  View() {
    _scrollController.addListener(_onScroll);
  }

I would like to test the _onScroll function:

 void _onScroll() {
    final maxScroll = _scrollController.position.maxScrollExtent;
    final currentScroll = _scrollController.position.pixels;
    if (maxScroll - currentScroll <= _scrollThreshold) {
      _bloc.dispatch(Fetch());
    }
  }

But I don't know how can I test it. This is what I tried so far:

  testWidgets('Should test the scroll',
      (WidgetTester tester) async {
await tester.pumpWidget(generateApp());
    await tester.pump();
    await tester.drag(find.byType(ListView), const Offset(0.0, -300));
    await tester.pump();
...

)}

but it doesn't call at all that function.

Upvotes: 26

Views: 26593

Answers (7)

yshean
yshean

Reputation: 441

For my case I tried both scrollUntilVisible and dragUntilVisible, but none worked. (maybe because of the nested scrollable widget). This worked for me for scrolling to the bottom of the list:

await tester.drag(
  find.byType(ListTile).first,
  const Offset(0, -100),
);

Remember to run await tester.pumpAndSettle() after that.

Upvotes: 0

Jitesh Mohite
Jitesh Mohite

Reputation: 34180

Scrolling can be tested using dragUntilVisible, which scrolls the widget till it gets visible on screen, just make sure the right delta is added for moving it vertically or horizontally.

 final expectedWidget = find.byText("Find me!");

  await tester.dragUntilVisible(
      expectedWidget, // what you want to find
      find.byType(ListView),
      // widget you want to scroll
      const Offset(0, 500) // delta to move
     );

Upvotes: 6

Oleg Safarov
Oleg Safarov

Reputation: 2345

As an alternative it's also possible to search for the ListView widget itself and retrieve its scroll controller to manipulate it directly:

final listView = tester.widget<ListView>(find.byType(ListView));
final ctrl = listView.controller;
ctrl.jumpTo(ctrl.offset + 300);
await tester.pumpAndSettle(duration);

Upvotes: 3

Gui Silva
Gui Silva

Reputation: 1441

for those using the new flutter_test lib, we also have the dragUntilVisible method:

await tester.dragUntilVisible(
    find.text('Earn mana!'), // what you want to find
    find.byKey(ValueKey('OnboardingCarousel')), // widget you want to scroll
    const Offset(-250, 0), // delta to move
);

Upvotes: 25

GtdDev
GtdDev

Reputation: 928

I highly recommend you to pay attention in the "Cartesian plane" of your screen/dragging movement.

Let me explain:

  1. You should use: await tester.drag(keyCartItemProduct1, Offset(-500.0, 0.0));
  2. However, your "Offset" Command, must obey the same "Cartesian direction" than your Dragging.

2.1) Therefore: (The command Offset uses Cartesian 'directions') - lets see: a) Left Dragging: Offset(-500.0, 0.0) b) Right Dragging: Offset(+500.0, 0.0) c) Up Dragging: Offset(0.0, +500.0) d) Down Dragging: Offset(0.0, -500.0)

Upvotes: 2

Avi Cohen
Avi Cohen

Reputation: 3414

If you pass the key parameter to the builder:

ListView.builder(key: Key('ListViewKey'),...);

Then finding by key:

await tester.drag(find.byKey(Key('ListViewKey')), const Offset(0.0, -300));
await tester.pump();

Will work.

Upvotes: 13

Jordan Davies
Jordan Davies

Reputation: 10861

You can create a TestGesture in your tests and perform a scroll that way.

final gesture = await tester.startGesture(Offset(0, 300)); //Position of the scrollview
await gesture.moveBy(Offset(0, -300)); //How much to scroll by
await tester.pump();

Upvotes: 16

Related Questions