Flutter test 处理滚动时使用 Key 查找 ListView
本文相关内容:
处理滚动 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
被测试代码:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp(
items: List<String>.generate(10000, (i) => 'Item $i'),
));
}
class MyApp extends StatelessWidget {
final List<String> items;
const MyApp({super.key, required this.items});
@override
Widget build(BuildContext context) {
const title = 'Long List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: const Text(title),
),
body: ListView.builder(
// Add a key to the ListView. This makes it possible to
// find the list and scroll through it in the tests.
key: const Key('long_list'),
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
items[index],
// Add a key to the Text widget for each item. This makes
// it possible to look for a particular item in the list
// and verify that the text is correct
key: Key('item_${index}_text'),
),
);
},
),
),
);
}
}
使用官方给的示例测试滚动时,使用的是 find.byType(Scrollable) 。
final listFinder = find.byType(Scrollable);
final itemFinder = find.byKey(const ValueKey('item_50_text'));
// Scroll until the item to be found appears.
await tester.scrollUntilVisible(
itemFinder,
500.0,
scrollable: listFinder,
);
但是如果画面有多个ListView或可滚动组件,就会出现下面的错误。
Bad state: Too many elements
这时一般会想到给某个 LivtView 设置 Key ,然后用 Key 来查找组件,
final listFinder = find.byKey(const ValueKey('long_list'));
很不幸,这时候会提示另外一个错误:
type 'ListView' is not a subtype of type 'Scrollable' in type
找了半天,在 Flutter 的 issue 中找到了解决方法。
主要代码:
final list = find.byKey(const ValueKey('long_list'));
final scrollable = find.byWidgetPredicate((w) => w is Scrollable);
final scrollableOfList = find.descendant(of: list, matching: scrollable);
scrollableOfList 为查找到的可滚动组件。
完整代码:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:untitled/scroll/main.dart';
void main() {
testWidgets('Counter increments smoke test', (tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(MyApp(
items: List<String>.generate(10000, (i) => 'Item $i'),
));
final list = find.byKey(const ValueKey('long_list'));
final scrollable = find.byWidgetPredicate((w) => w is Scrollable);
final scrollableOfList = find.descendant(of: list, matching: scrollable);
final itemFinder = find.byKey(const ValueKey('item_400_text'));
// Scroll until the item to be found appears.
await tester.scrollUntilVisible(
itemFinder,
500.0,
scrollable: scrollableOfList,
duration: const Duration(milliseconds: 100),
);
// Verify that the item contains the correct text.
expect(itemFinder, findsOneWidget);
});
}
测试结果:
00:10 +1: All tests passed!