如何在小部件测试中找到屏幕外的 ListView 子项?
How to find off-screen ListView child in widget tests?
在 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
它会起作用。
有人知道为什么会这样吗?这是一个错误吗?有解决办法吗?
测试应该像您的应用一样运行,否则,您的测试将变得无用(因为您没有测试真实的行为)。
因此,这不是错误。
您必须在测试中手动滚动 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
在您的 Finder 中将 skipOffstate
设置为 false
是一种方法。试试这个:
expect(find.text("Find me!", skipOffstage: false), findsOneWidget);
我强烈建议您注意 screen/dragging 运动的“笛卡尔平面”。
让我解释一下:
- 你应该使用:
await tester.drag(keyCartItemProduct1, Offset(-500.0, 0.0));
- 但是,您的“偏移”命令必须遵循与拖动相同的“笛卡尔方向”。
2.1) 因此:(Offset 命令使用笛卡尔 'directions')- 让我们看看:
a) 左拖动:Offset(-500.0, 0.0)
b) 向右拖动:Offset(+500.0, 0.0)
c) 向上拖动:Offset(0.0, +500.0)
d) 向下拖动:Offset(0.0, -500.0)
dragUntilVisible
帮助滚动 Listview 或 SingleChildScrollView 滚动直到预期的小部件可见
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));
尝试将 skipOffstage 设置为 false 的代码,它工作正常。
testWidgets('Find widget off of screen', (WidgetTester tester) async {
await tester.pumpWidget(yourScreen);
expect(find.byKey(const Key('widgetname'), skipOffstage: false), findsOneWidget); });
在 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
它会起作用。
有人知道为什么会这样吗?这是一个错误吗?有解决办法吗?
测试应该像您的应用一样运行,否则,您的测试将变得无用(因为您没有测试真实的行为)。 因此,这不是错误。
您必须在测试中手动滚动 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
在您的 Finder 中将 skipOffstate
设置为 false
是一种方法。试试这个:
expect(find.text("Find me!", skipOffstage: false), findsOneWidget);
我强烈建议您注意 screen/dragging 运动的“笛卡尔平面”。
让我解释一下:
- 你应该使用: await tester.drag(keyCartItemProduct1, Offset(-500.0, 0.0));
- 但是,您的“偏移”命令必须遵循与拖动相同的“笛卡尔方向”。
2.1) 因此:(Offset 命令使用笛卡尔 'directions')- 让我们看看: a) 左拖动:Offset(-500.0, 0.0) b) 向右拖动:Offset(+500.0, 0.0) c) 向上拖动:Offset(0.0, +500.0) d) 向下拖动:Offset(0.0, -500.0)
dragUntilVisible
帮助滚动 Listview 或 SingleChildScrollView 滚动直到预期的小部件可见
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));
尝试将 skipOffstage 设置为 false 的代码,它工作正常。
testWidgets('Find widget off of screen', (WidgetTester tester) async {
await tester.pumpWidget(yourScreen);
expect(find.byKey(const Key('widgetname'), skipOffstage: false), findsOneWidget); });