@@ -6,7 +6,7 @@ import 'package:borneo_app/core/services/devices/device_module_registry.dart';
66import 'package:flutter/material.dart' ;
77import 'package:flutter_test/flutter_test.dart' ;
88import 'package:integration_test/integration_test.dart' ;
9- import 'package:sembast/sembast_memory.dart' ;
9+ import 'package:sembast/sembast_memory.dart' hide Finder ;
1010import 'package:shared_preferences/shared_preferences.dart' ;
1111
1212import 'package:borneo_app/main.dart' as app;
@@ -41,6 +41,21 @@ Future<Widget> _buildTestApp({IDeviceModuleRegistry? registry}) async {
4141// Tests
4242// ---------------------------------------------------------------------------
4343
44+ /// Repeatedly pumps the tester until [finder] is found or the [timeout]
45+ /// expires. This is more reliable than `pumpAndSettle` when the UI shows an
46+ /// indefinite animation (e.g. a loading spinner) that would otherwise keep
47+ /// scheduling frames.
48+ Future <void > _waitFor (WidgetTester tester, Finder finder, {Duration timeout = const Duration (seconds: 5 )}) async {
49+ final end = DateTime .now ().add (timeout);
50+ while (DateTime .now ().isBefore (end)) {
51+ await tester.pump (const Duration (milliseconds: 100 ));
52+ if (tester.any (finder)) return ;
53+ }
54+ // Final check to produce a sensible failure message
55+ await tester.pump ();
56+ expect (tester.any (finder), true , reason: 'Expected $finder to appear within $timeout ' );
57+ }
58+
4459void main () {
4560 IntegrationTestWidgetsFlutterBinding .ensureInitialized ();
4661
@@ -62,6 +77,11 @@ void main() {
6277 await tester.tap (find.byIcon (Icons .device_hub_outlined));
6378 await tester.pumpAndSettle ();
6479
80+ // Devices screen should be fully initialized before we continue. The title
81+ // contains the current scene name which is "My Home" in the fresh
82+ // in-memory database.
83+ await _waitFor (tester, find.text ('Devices in My Home' ));
84+
6585 // open add menu and select Add Devices Group
6686 await tester.tap (find.byIcon (Icons .add_outlined));
6787 await tester.pumpAndSettle ();
@@ -71,12 +91,9 @@ void main() {
7191 // fill in group name and submit
7292 await tester.enterText (find.byKey (const Key ('field_group_name' )), 'Test Group' );
7393 await tester.tap (find.byKey (const Key ('btn_submit' )));
74- // Give DB write + EventBus async delivery + reload time to complete.
94+ // give database and event bus a moment to complete, then wait for list update
7595 await tester.pump (const Duration (milliseconds: 500 ));
76- await tester.pumpAndSettle ();
77-
78- // verify group shows up in list
79- expect (find.text ('Test Group' ), findsOneWidget);
96+ await _waitFor (tester, find.text ('Test Group' ));
8097
8198 // edit the group
8299 await tester.tap (find.byKey (const Key ('btn_edit_group_Test Group' )));
@@ -86,7 +103,7 @@ void main() {
86103 await tester.enterText (find.byKey (const Key ('field_group_name' )), 'Updated Group' );
87104 await tester.tap (find.byKey (const Key ('btn_submit' )));
88105 await tester.pump (const Duration (milliseconds: 500 ));
89- await tester. pumpAndSettle ( );
106+ await _waitFor ( tester, find. text ( 'Updated Group' ) );
90107
91108 expect (find.text ('Updated Group' ), findsOneWidget);
92109
@@ -101,8 +118,6 @@ void main() {
101118 // confirm deletion
102119 await tester.tap (find.byKey (const Key ('btn_confirm_delete' )));
103120 await tester.pump (const Duration (milliseconds: 500 ));
104- await tester.pumpAndSettle ();
105-
106121 // group should no longer be present
107122 expect (find.text ('Updated Group' ), findsNothing);
108123 });
0 commit comments