I have some customized TextFiels and they are for entering a pin and I called them PinInputField
. When I'm running integration test using flutter drive, all of the input fields will receive given text, except last one and stops running test.
Here is the code:
P.s: the I'm using HookWidget
final focusNodes = List.generate(6, (_) => new FocusNode());
final values = List.generate(6, (_) => useState<String>(''));
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
for (int i = 0; i < values.length; i++)
PinInputField(
key: ValueKey('$i'),
width: MediaQuery.of(context).size.width / 11.71,
height: 80,
fontSize: 50,
marginRight: 16,
input: values[i],
focusNode: focusNodes[i],
nextFocusNode: i == 5 ? null : focusNodes[i + 1],
)
],
)
and here is the tests:
test('test main card settings items', () async {
final cardSettingsItem = find.byValueKey('settings.cardSettings');
final mainSettingsList = find.byValueKey('mainSettingsList');
final profileButton = find.byValueKey('Profile');
final changePinButton = find.byValueKey('Cambiar pin');
final changePinInputField0 = find.byValueKey('0');
final changePinInputField1 = find.byValueKey('1');
final changePinInputField2 = find.byValueKey('2');
final changePinInputField3 = find.byValueKey('3');
final changePinInputField4 = find.byValueKey('4');
final changePinInputField5 = find.byValueKey('5');
final changePinScreenButton = find.byValueKey('changePinScreenButton');
sleep(Duration(seconds: 3));
await driver.tap(profileButton);
sleep(Duration(seconds: 2));
await driver.scrollIntoView(mainSettingsList);
sleep(Duration(seconds: 3));
await driver.tap(cardSettingsItem);
sleep(Duration(seconds: 3));
await driver.tap(changePinButton);
sleep(Duration(seconds: 4));
await driver.tap(changePinInputField0);
sleep(Duration(seconds: 2));
await driver.enterText("0");
sleep(Duration(seconds: 1));
await driver.tap(changePinInputField1);
sleep(Duration(seconds: 2));
await driver.enterText("1");
sleep(Duration(seconds: 1));
await driver.tap(changePinInputField2);
sleep(Duration(seconds: 2));
await driver.enterText("2");
sleep(Duration(seconds: 1));
await driver.tap(changePinInputField3);
sleep(Duration(seconds: 2));
await driver.enterText("3");
sleep(Duration(seconds: 1));
await driver.tap(changePinInputField4);
sleep(Duration(seconds: 2));
await driver.enterText("4");
sleep(Duration(seconds: 4));
await driver.tap(changePinInputField5);
sleep(Duration(seconds: 1));
await driver.enterText("5");
sleep(Duration(seconds: 5));
await driver.tap(changePinScreenButton);
sleep(Duration(seconds: 4));
});
and here is the log:
DriverError: Failed to fulfill Tap due to remote error
Original error: Bad state: The client closed with pending request "ext.flutter.driver".
Original stack trace:
#0 new Client.withoutJson.<anonymous closure> (package:json_rpc_2/src/client.dart:70:24)
#1 StackZoneSpecification._run (package:stack_trace/src/stack_zone_specification.dart:209:15)
#2 StackZoneSpecification._registerCallback.<anonymous closure> (package:stack_trace/src/stack_zone_specification.dart:119:48)
#3 _rootRun (dart:async/zone.dart:1120:38)
#4 _CustomZone.run (dart:async/zone.dart:1021:19)
#5 _FutureListener.handleWhenComplete (dart:async/future_impl.dart:150:18)
#6 Future._propagateToListeners.handleWhenCompleteCallback (dart:async/future_impl.dart:609:39)
#7 Future._propagateToListeners (dart:async/future_impl.dart:665:37)
#8 Future._propagateToListeners (dart:async/future_impl.dart:566:9)
#9 Future._completeWithValue (dart:async/future_impl.dart:483:5)
#10 Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:513:7)
#11 StackZoneSpecification._run (package:stack_trace/src/stack_zone_specification.dart:209:15)
#12 StackZoneSpecification._registerCallback.<anonymous closure> (package:stack_trace/src/stack_zone_specification.dart:119:48)
#13 _rootRun (dart:async/zone.dart:1124:13)
#14 _CustomZone.run (dart:async/zone.dart:1021:19)
#15 _CustomZone.runGuarded (dart:async/zone.dart:923:7)
#16 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:963:23)
#17 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
#18 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
#19 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:391:30)
#20 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:416:5)
#21 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:172:12)
This issue mostly occurs when the test times out before it is actually completed. The default timeout used for a test to run is 30 seconds, here your sleep durations add up to more than 30 seconds, hence the connection closed with pending requests.
I don't understand why to sleep for a certain duration after each action, may be you can reduce/remove sleep. If sleeps are mandatory for your case try to pass the appropriate timeout
to the test.
Example:
test(
'test main card settings items',
() async {
final cardSettingsItem = find.byValueKey('settings.cardSettings');
final mainSettingsList = find.byValueKey('mainSettingsList');
final profileButton = find.byValueKey('Profile');
final changePinButton = find.byValueKey('Cambiar pin');
final changePinInputField0 = find.byValueKey('0');
final changePinInputField1 = find.byValueKey('1');
final changePinInputField2 = find.byValueKey('2');
final changePinInputField3 = find.byValueKey('3');
final changePinInputField4 = find.byValueKey('4');
final changePinInputField5 = find.byValueKey('5');
final changePinScreenButton = find.byValueKey('changePinScreenButton');
sleep(Duration(seconds: 3));
await driver.tap(profileButton);
sleep(Duration(seconds: 2));
await driver.scrollIntoView(mainSettingsList);
sleep(Duration(seconds: 3));
await driver.tap(cardSettingsItem);
sleep(Duration(seconds: 3));
await driver.tap(changePinButton);
sleep(Duration(seconds: 4));
await driver.tap(changePinInputField0);
sleep(Duration(seconds: 2));
await driver.enterText("0");
sleep(Duration(seconds: 1));
await driver.tap(changePinInputField1);
sleep(Duration(seconds: 2));
await driver.enterText("1");
sleep(Duration(seconds: 1));
await driver.tap(changePinInputField2);
sleep(Duration(seconds: 2));
await driver.enterText("2");
sleep(Duration(seconds: 1));
await driver.tap(changePinInputField3);
sleep(Duration(seconds: 2));
await driver.enterText("3");
sleep(Duration(seconds: 1));
await driver.tap(changePinInputField4);
sleep(Duration(seconds: 2));
await driver.enterText("4");
sleep(Duration(seconds: 4));
await driver.tap(changePinInputField5);
sleep(Duration(seconds: 1));
await driver.enterText("5");
sleep(Duration(seconds: 5));
await driver.tap(changePinScreenButton);
sleep(Duration(seconds: 4));
},
timeout: Timeout(
Duration(minutes: 2),
),
);
Hope that helps!
I've struggled with the default 30 sec timeout as well. And it only was a problem when the Flutter Driver tests were run on remote CI/CD. Locally test ran great. I did two things that seem to work for remote CI/CD:
timeout
@Hemanth prescribed above. Thanks @Hemanth 🙏🏽!clearTimeline()
at the start of each test. test('Home page should properly work', () async {
await driver.clearTimeline();
await HomePage(driver).appears()
.then((a) => a.exploreHomePage());
},
timeout: Timeout(
Duration(minutes: 2),
),
);
Note:
Implementing timeout
& clearTimeline()
allowed the longer running tests to complete. But I would recommend adding to each test regardless of size. I too initially tried sleeps
, and ended up removing them all after using timeout
& clearTimeline()
.
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With