Поиск виджета внутри CustomScrollView в тесте Flutter


Я обнаружил ошибку при попытке протестировать приложение Flutter. У меня есть настраиваемый виджет, который находится внизу (вне первого окна просмотра) виджета. В своем тесте я хочу убедиться, что он действительно существует.
Я уже пробовал использовать а также WidgetTester.drag(как это было сделано при тестировании фреймворка флаттера). Кроме того, я попытался провести рефакторинг своих тестов с помощью FlutterDriverчто просто полностью испортило все остальное.
Как прокрутить тест до конца?
Это минимальное воспроизведение показывает приложение, содержащее виджет-контейнер высотой в один экран (так что виджет, который я хочу найти, находится вне начального представления)

      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,
      ),
    );
  }
}

Вот тест, который я изначально написал, чтобы найти виджет, который, конечно же, не удался.

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

В этой итерации я использовал WidgetTester.scrollUntilVisible функция, но получил ошибку ниже.

      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)

Я благодарен за любую помощь или предложения о том, как решить эту проблему и успешно протестировать мой CustomScrollView

2 ответа

У меня была такая же проблема, и в итоге я использовал метод dragUntilVisible() вместо scrollUntilVisible().

Пример прокрутки вниз, пока виджет не станет видимым:

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

Просто используйте " await tester.ensureVisible(find.byKey(Key("key_of_the_element"))); " перед нажатием. Он будет прокручиваться до тех пор, пока данный элемент не станет видимым. Это лучше, чем dragUntilVisible или ScrollUntilVisible, потому что drageUntilVisble не будет работать с виджетами без рендеринга, а ScrollUntilVisible не будет работать с виджетами без прокрутки.

пакет :flutter_test/src/controller.dart

Будущее обеспечениеВиджет (поиск Finder)
Содержит класс: WidgetController
Тип : Будущая функция (Finder)
Учитывая виджет W, указанный в поиске, и прокручиваемый виджет S в его дереве предков, это прокручивает S, чтобы сделать W видимым. Обычно искатель для этого метода должен иметь маркировкуskipOffstage: false, чтобы Finder правильно обрабатывал виджеты, находящиеся за пределами экрана. Это не работает, когда S достаточно длинный, а W достаточно далеко от отображаемой части S, так что S еще не кэшировал элемент W. В такой ситуации рассмотрите возможность использования ScrollUntilVisible. См. также: Scrollable.ensureVisible — производственный API, используемый для реализации этого метода.