Flutter test 处理滚动时使用 Key 查找 ListView

531 阅读1分钟

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 中找到了解决方法。

[integration_test] scrollUntilVisible example with multiple scrollviews · Issue #85046 · flutter/flutter · GitHub

主要代码:

    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!