如何在Flutter集成测试中等待Finder可见后执行下一段代码?

9

信息:
我创建了一个样例Flutter单元测试,用于测试登录界面,在该界面有电子邮件和密码输入框以及登录按钮。

要求:
需要测试虚假情况,为此,我根据以下步骤编写了代码。

  1. 打开main.dart文件
  2. 填写电子邮件和密码字段
  3. 点击登录按钮。在此处调用API,并在屏幕上显示加载器,直到API获得成功或失败响应为止。
  4. 需要检查是否显示带有消息的失败对话框。

问题/查询:
现在当调用API时,我想等待加载器可见,直到加载器消失。因此,目前我只是放置了手动延迟以执行下一个代码,但我想使其动态化。所以,请让我知道如何基于加载器可见性设置动态延迟?

代码:

void main() {
  group('App Test', () {
    IntegrationTestWidgetsFlutterBinding.ensureInitialized();

    testWidgets('Login Fail Test', (WidgetTester tester) async {
      await app.main();
      await tester.pumpAndSettle();

      await tester.pump(new Duration(seconds: 2));

      final emailField = find.byType(TextFormField).first;
      final passwordField = find.byType(TextFormField).last;
      final loginButton = find.byType(RaisedButton).first;

      await tester.enterText(emailField, 'Test');
      await tester.pumpAndSettle();
      await tester.pump(new Duration(seconds: 1));

      await tester.enterText(passwordField, 'Test123');
      await tester.pumpAndSettle();
      await tester.pump(new Duration(seconds: 1));

      await tester.tap(loginButton);
      await tester.pumpAndSettle();
      await tester.pump(new Duration(seconds: 3));

     
      final dialog = find.byType(AlertDialog).first;
      await tester.element(dialog);
      await tester.pumpAndSettle();
      await tester.pump(new Duration(seconds: 1));

      final dialogButton = find.byType(FlatButton).first;
      await tester.tap(dialogButton);
      await tester.pumpAndSettle();
      await tester.pump(new Duration(seconds: 2));
    });
}

目前还没有官方支持,Flutter SDK 中有几个问题https://github.com/flutter/flutter/issues/73355 显然目前只有一个解决方法,但是在测试运行器中集成得不太好。 - Leonardo
2个回答

5

我有一个名为utils.dart的文件,用于实现这样的功能。在这种情况下,我使用以下函数,它将基本上轮询直到发现器有效。

// utils.dart

Future<void> pumpUntilFound(
  WidgetTester tester,
  Finder finder, {
  Duration timeout = const Duration(seconds: 10),
}) async {
  bool timerDone = false;
  final timer = Timer(timeout, () => timerDone = true);
  while (timerDone != true) {
    await tester.pump();

    final found = tester.any(finder);
    if (found) {
      timerDone = true;
    }
  }
  timer.cancel();
}

今日免费次数已满, 请开通会员/明日再来
// my_test.dart

final fab = find.byKey(const ValueKey('fab'));
await pumpUntilFound(widgetTester, fab);
expect(fab, findsOneWidget);

这样仍然无法实现动态等待,因为我们传递的是固定的超时时间,一旦等待到达该时间就会退出。 - Patel Pinkal
@PatelPinkal 这是动态的,因为它会等待 Finder 被找到,你可以增加超时时间,直到你认为等待的时间合适。如果你的 API 请求需要超过 10 秒才能解决,那么很可能出现了错误,但你可以调整超时时间。 - baconcheese113
但最终每次计时器执行时都会调用一个泵,直到找到查找器为止,我认为这不是一个好的做法。 - Patel Pinkal
2
你的问题是关于等待“Finder可见”的,没有一种方法可以使Finder在不渲染新帧的情况下变得可见(这就是pump()所做的)。我同意监视特定的网络请求以等待其完成会更有效,但上面的答案是你问题的解决方案。 - baconcheese113

-2

尝试像这样包装:

testWidgets('test',
    (WidgetTester tester) async {
    await tester.runAsync(() async {

      // test code here

    });
 });

如果你使用:

await tester.pumpAndSettle();

然后:

  final widget = find.byKey(Key('whatever'));

它将动态查找


我不想查找任何小部件或查找器。我需要等待小部件可见,而不是通过持续时间的静态延迟。 - Patel Pinkal

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