Finding a widget inside of a CustomScrollView in Flutter test

Viewed 952


I have encountered an error when trying to test my Flutter App. I have a custom widget that is at the bottom (out of the first viewport) of a CustomScrollView widget. In my test, I want to verify that it is actually there.
I have already tried to use WidgetTester.scrollUntilVisible as well as WidgetTester.drag (like it was done in the tests of the flutter framework). Additionally, I tried to refactor my tests with the FlutterDriver which just messed everything else up completely.
How do I scroll to the bottom of a CustomScrollView inside of a test?
This minimal reproduction shows the application containing the CustomScrollView which has a Container widget with the height of one screen (so that the widget I want to find is out of the initial view)

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          body: CustomScrollView(
        slivers: [
          SliverToBoxAdapter(
            child: Container(
              height: MediaQuery.of(context).size.height,
            ),
          ),
          MyWidget(),
        ],
      )),
    );
  }
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SliverToBoxAdapter(
      child: Container(
        height: 100,
        width: 100,
      ),
    );
  }
}

Here is the test I initially wrote to find the widget, which failed of course.

void main() {
  testWidgets('main contains mywidget', (WidgetTester tester) async {
    // arange
    await tester.pumpWidget(MyApp());
    // act
    final myWidget = find.byType(MyWidget);
    // assert
    expect(myWidget, findsOneWidget);
  });
}

In this iteration, I used the WidgetTester.scrollUntilVisible function but got the error below.

void main() {
  testWidgets('main contains mywidget', (WidgetTester tester) async {
    // arange
    await tester.pumpWidget(MyApp());
    // act
    final myWidget = find.byType(MyWidget);
    final customScrollView = find.byType(CustomScrollView);
    await tester.scrollUntilVisible(myWidget, 100,
        scrollable: customScrollView);
    await tester.pump();
    // assert
    expect(myWidget, findsOneWidget);
  });
}
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following _CastError was thrown running a test:
type 'CustomScrollView' is not a subtype of type 'Scrollable' in type cast

When the exception was thrown, this was the stack:
#0      WidgetController.widget (package:flutter_test/src/controller.dart:66:44)
#1      WidgetController.scrollUntilVisible.<anonymous closure> (package:flutter_test/src/controller.dart:995:15)
#2      WidgetController.scrollUntilVisible.<anonymous closure> (package:flutter_test/src/controller.dart:993:39)
#5      TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:72:41)
#6      WidgetController.scrollUntilVisible (package:flutter_test/src/controller.dart:993:27)
#7      main.<anonymous closure> (file:///C:/Users/X/test_example/test/main_test.dart:12:18)
<asynchronous suspension>
<asynchronous suspension>
(elided 3 frames from dart:async and package:stack_trace)

I appreciate any help or suggestions on how to fix this issue and successfully test my CustomScrollView

1 Answers

I had the same problem and I ended up using the dragUntilVisible() method instead of scrollUntilVisible().

Example of scrolling down until the widget is visible:

await tester.dragUntilVisible(myWidget, customScrollView, Offset(0, -500));
Related