Reputation: 3268
I am trying to write some integration tests that start off with a login attempt then proceeds to navigate the app a bit to a certain page. The attempt to sign in actually succeeds but after that my attempts to find any widgets fails so I cannot navigate further.
After the sign-in the page the app automatically navigates away to the next page in the app correctly but then my test script cannot find any widgets on that page even though I can see them in the android emulator onscreen.
My app_test.dat file looks like this:
import ...
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('sign in : ', () {
testWidgets('try to SIGN IN and open the menu ',
(WidgetTester tester) async {
app.main();
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await tester.pumpAndSettle();
expect(find.text('SIGN IN', skipOffstage: false), findsWidgets);
expect(find.byKey(Key('loginPagePasswordField')), findsOneWidget);
expect(find.byKey(Key('loginPageEmailField')), findsOneWidget);
print('found fields');
await tester.enterText(
find.byKey(Key('loginPageEmailField')), '[email protected]');
await tester.enterText(
find.byKey(Key('loginPagePasswordField')), 'myname123zxc');
print('entered text');
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pump();
print('entered DONE');
await tester.pumpAndSettle(const Duration(milliseconds: 5000));
await tester.pumpAndSettle();
// Now try to find the menu icon button
var x = find.byTooltip('Open navigation menu');
expect(x, findsOneWidget); // this fails but is needed to navigate the app
print('find tab1 ');
// Now try to find the 'ASD' Tab
final tabFinder = find.text('ASD', skipOffstage: false);
expect(tabFinder, findsWidgets); // this also fails
});
});
}
and my f doctor (I use fvm):
[✓] Flutter (Channel stable, 2.8.0, on macOS 12.1 21C52 darwin-arm, locale en-CA)
[✓] Android toolchain - develop for Android devices (Android SDK version 32.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 13.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] VS Code (version 1.63.0)
[✓] Connected device (2 available)
• No issues found!
Upvotes: 1
Views: 4434
Reputation: 3268
It seems that the trick is that the AppBar's default "leading" widget or the default leading widget's default tooltip is not present when the integration test is run. When the app is run in debug-mode in the emulator it is there - it can be found with a debug-watch on MaterialLocalizations.of(context).openAppDrawerTooltip
. That watch does not find the tooltip when I run debug on the test file - then again no watches seem to work in that case.
The fix is to manually add the "leading" widget into the AppBar like so:
appBar: AppBar(
title: "my title",
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: Icon(Icons.menu),
onPressed: () {
Scaffold.of(context).openDrawer();
},
tooltip: 'Open navigation menu',
);
},
),
...
Now, on to the next problem - why does the next test in the group fail to find any widgets?
Upvotes: 0
Reputation: 16699
There are several possible reasons why the widget is not found in this particular case:
Tooltip
widget.Now what are possible fixes.
If the widget is on the screen and is visible to you doesn't meen that it is visible to the test driver - from my experience it is a pretty common situation. You can try to use tester.ensureVisible
to make it visible for sure. Or actually scroll the content to make sure it is visible with either tester.fling
, tester.scrollUntilVisible
or tester.dragUntilVisible
.
Check you tooltip string. I would recommend you not to use findByTooltip
in this way - you may not know the excat locale of the device and if there will be Localization enabled for the app - the finder will fail. If you are completely sure that there won't be a localization in the app - create a static string with a tooltip and use it both in the code and in tests - this way you will be sure the string is the same. With localizations - use InheritedWidget
approach and retrieve strings from context via appLocalizations.of(context)
both in the implementation and tests. But the actual proposition here is not to use findByTooltip
at all. findByKey
is much more reliable because it is independent from context locale and manual entering mistake - just use Keys as I suggested before - create static consts keys and use the same const both in your code and tests.
Check if the message
field of your Tooltip
is filled and is the same you try to find.
Pump a bit more - maybe it will help. Also try to use pump
with long duration and then pumpAndSettle
with default duration directly one after the other - sometimes it helps.
Try to run tests on real device.
The general answer to your question is that finder finds widgets if everything is correctly coded and there is such a widget on the screen. But I understand why it is somehow problematic - I have written several thousands of lines of flutter integration tests and I have seen all kinds of human mistakes(mine includingly), weird driver/tester/finder behaviours and device/os/framewok specific cases.
Upvotes: 2