import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:get/get.dart'; import 'package:eaimar/data/services/id_verify_service.dart'; import 'package:eaimar/modules/common/widgets/id_verify_dialog.dart'; /// 回归测试:实名认证弹窗关闭时不能炸。 /// /// 早先的实现把 TextEditingController 放在 showIdVerifyDialog() 里, /// `await Get.dialog(...)` 一返回就 dispose——但那时弹窗还在播退场动画、 /// TextField 仍挂在树上,于是元素树被破坏,真机上红屏 /// `'_dependents.isEmpty': is not true`。 /// /// 控制器改由 State 持有、在 State.dispose() 里释放后,本测试通过。 void main() { setUp(() { Get.testMode = true; Get.put(IdVerifyService()); }); tearDown(Get.reset); Future pumpHost(WidgetTester tester) async { await tester.pumpWidget( ScreenUtilInit( designSize: const Size(390, 844), builder: (_, __) => const GetMaterialApp(home: Scaffold(body: SizedBox())), ), ); await tester.pump(); } testWidgets('弹窗打开后关闭,不应抛异常(控制器提前释放会在这里炸)', (tester) async { await pumpHost(tester); // 不 await —— 和真实调用一样,弹窗自己走完生命周期 final future = showIdVerifyDialog(); await tester.pumpAndSettle(); expect(find.byType(IdVerifyDialog), findsOneWidget); // 取消关闭,走完整的退场动画 await tester.tap(find.text('cancel')); await tester.pumpAndSettle(); expect(find.byType(IdVerifyDialog), findsNothing); expect(tester.takeException(), isNull, reason: '关闭弹窗过程中不应有异常'); expect(await future, isFalse); }); testWidgets('姓名为空时给出错误提示,且不关闭弹窗', (tester) async { await pumpHost(tester); showIdVerifyDialog(); await tester.pumpAndSettle(); await tester.tap(find.text('idVerifySubmit')); await tester.pumpAndSettle(); // 弹窗仍在(没被错误地关掉),且没有异常 expect(find.byType(IdVerifyDialog), findsOneWidget); expect(tester.takeException(), isNull); }); }