You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter集成测试中如何等待加载器消失后再执行后续测试代码?

解决方案

你可以通过监听Loader组件的可见状态,配合循环pump的方式实现动态等待,完全替代固定延迟,具体实现如下:

第一步:给Loader组件添加唯一标识

先给登录页的加载动画组件设置唯一的Key,方便测试时精准定位,示例代码:

// 登录页里的Loader组件
CircularProgressIndicator(
  key: Key('login_loading_indicator'),
)

如果你的Loader是自定义组件,直接给自定义组件加Key即可。

第二步:封装动态等待工具方法

封装通用的等待组件消失的方法,可复用在所有需要等待的测试场景中:

import 'dart:async';

Future<void> waitForWidgetDisappear(
  WidgetTester tester,
  Finder targetFinder, {
  // 最大等待时长,可根据实际接口响应调整
  Duration maxWaitTime = const Duration(seconds: 10),
  // 每轮检查的间隔时间
  Duration checkInterval = const Duration(milliseconds: 200),
}) async {
  final deadline = DateTime.now().add(maxWaitTime);
  // 循环检查组件是否还存在
  while (DateTime.now().isBefore(deadline)) {
    if (targetFinder.evaluate().isEmpty) {
      // 组件已消失,直接返回
      return;
    }
    // 间隔指定时间后再渲染一帧检查
    await tester.pump(checkInterval);
  }
  // 超时抛出异常,方便排查问题
  throw TimeoutException('等待组件超时,目标组件未在$maxWaitTime内消失');
}

第三步:替换原有固定延迟代码

修改你的测试代码,把点击登录后的固定3秒延迟,替换为动态等待逻辑,优化后的完整测试代码如下:

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

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

      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.enterText(passwordField, 'Test123');
      await tester.pumpAndSettle();

      await tester.tap(loginButton);
      // 先触发一帧渲染,让Loader正常显示
      await tester.pump();
      // 动态等待登录Loader消失
      await waitForWidgetDisappear(tester, find.byKey(Key('login_loading_indicator')));
      // 等待页面渲染完全稳定
      await tester.pumpAndSettle();

      final dialog = find.byType(AlertDialog).first;
      expect(dialog, findsOneWidget);
      // 校验弹窗提示内容示例,可根据你的实际文案调整
      expect(find.descendant(of: dialog, matching: find.text('账号或密码错误')), findsOneWidget);

      final dialogButton = find.byType(FlatButton).first;
      await tester.tap(dialogButton);
      await tester.pumpAndSettle();
    });
}

补充说明

  • 如果你不想给Loader加Key,也可以用find.byType(CircularProgressIndicator)来定位Loader,但如果页面内存在多个同类型组件时会出现定位错误,更推荐用Key的方式精准定位。
  • 原来填写输入框后的固定1秒延迟可以直接去掉,pumpAndSettle已经会等待输入相关的动画完成。

内容的提问来源于stack exchange,提问作者Patel Pinkal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 02:06:02