如何在小部件测试中查找屏幕外的ListView子项?

14
在ListView中显示多个子项时,如果一个子项不在屏幕上,它就无法被小部件测试找到。以下是一个完整的示例:

main.dart

import 'package:flutter/material.dart';

void main() => runApp(App());

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: Scaffold(body: Test()));
  }
}

class Test extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
        Container(
          height: 600,
          color: Colors.red,
        ),
        Text("Find me!"),
      ],
    );
  }
}

main_test.dart

import 'package:flutter_app/main.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets("Find text", (WidgetTester tester) async {
    final testableWidget = App();

    await tester.pumpWidget(testableWidget);

    expect(find.text("Find me!"), findsOneWidget);
  });
}

这个测试失败了,但是如果我将 main.dart 中 Container 的高度更改为 599 就可以通过测试。
有人知道为什么会发生这种情况吗?这是一个 bug 吗?有没有解决的方法?
5个回答

9

将Finder中的skipOffstate设置为false是一种方法。尝试这样做:

expect(find.text("Find me!", skipOffstage: false), findsOneWidget);

2
建议编辑:我认为skipOffstate不再是ensureVisible方法的参数:https://api.flutter.dev/flutter/widgets/Scrollable/ensureVisible.html - Adrien Arcuri
“skipOffstage” 简化了我的许多测试,我太喜欢它了! :D - Randomize

9

测试应该像您的应用程序一样运行,否则,您的测试将变得毫无用处(因为您没有测试实际行为)。 因此,这不是一个错误。

您必须在测试中手动滚动 ListView 以使其加载更多小部件。

可以使用 tester 实现此操作:

final gesture = await tester.startGesture(Offset.zero /* THe position of your listview */ );
// Manual scroll
await gesture.moveBy(const Offset(0, 100));

await tester.pump(); // flush the widget tree 

9
值得一提的是,您还可以拖动列表视图中的小部件:await tester.drag(find.byType(Container), Offset(0.0, -200)); await tester.pump(); - Jordan Davies

1

dragUntilVisible 函数可以帮助滚动 Listview 或 SingleChildScrollView 直到目标 Widget 可见。

     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
          duration: Duration(seconds: 2));

1

我强烈建议您关注屏幕/拖动运动的"笛卡尔平面"。

让我解释一下:

  1. 你应该使用: await tester.drag(keyCartItemProduct1, Offset(-500.0, 0.0));
  2. 然而,你的“Offset”命令必须遵守相同的“笛卡尔方向”和你的拖动。

2.1) 因此:(Offset命令使用笛卡尔'方向') - 让我们看看: a) 向左拖动: Offset(-500.0, 0.0) b) 向右拖动: Offset(+500.0, 0.0) c) 向上拖动: Offset(0.0, +500.0) d) 向下拖动: Offset(0.0, -500.0)


0

尝试将 skipOffstage 设置为 false,代码可以正常工作。

testWidgets('Find widget off of screen', (WidgetTester tester) async {

await tester.pumpWidget(yourScreen);
expect(find.byKey(const Key('widgetname'), skipOffstage: false), findsOneWidget); });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接