How to define app flow in flutter_driver automation testing? - flutter

How can I detect different screens and on the basis of it perform some testing. For example, If i am having a login screen in my app and if it's already signed in then different page may open after starting the app.How can I detect different screens and perform testing on it.
I am using flutter_driver for testing.
test("Home", ()async{
await driver.runUnsynchronized(() async {
await driver.waitFor(find.text("login"));
await driver.tap(find.text("login"));
});
});
test("Game Results", ()async{
await driver.runUnsynchronized(() async {
await driver.waitFor(find.text("Configure your team for the next game"));
await driver.scroll(find.text("success"), 0, -300, Duration(milliseconds: 500));
await driver.tap(find.text("success"));
});

Related

Flutter test widgets, go to another screen failed

I'm writting my very first widget tests in dart. I have to check if clicking on a button bring us to the next screen.
What am I doing wrong here?
testWidgets('Tapping staring the meeting button leads to conference screen', (widgetTester) async {
await widgetTester.pumpWidget(const MaterialApp(home: WelcomeScreen()));
await widgetTester.enterText(find.byKey(const Key('nameInput')), 'User');
await widgetTester.enterText(find.byKey(const Key('titleInput')), 'Title');
await widgetTester.enterText(find.byKey(const Key('passwordInput')), 'Password');
expect(find.byType(CallToActionButton), findsOneWidget);
await widgetTester.tap(find.byType(CallToActionButton));
await widgetTester.pump();
expect(find.byType(ConferenceScreen), findsOneWidget);
});

How to wait until the Finder is visible for next code execution in Flutter integration test?

Information:
I have created a sample Flutter unit test to test the login screen where I have email & password as input field and a login button.
Requirement:
Need to test false cases and for that, I have written code as per the below steps.
Open main.dart
Filled the email & password field
onTap event is done on the login button. Over here API will be called and loader is displayed on the screen until API gets a success or failure response.
Need to check if failure dialog is displayed with a message.
Issue/Query:
Now when the API is calling I want to wait when the loader is visible until the loader is gone. So, as of now I just put a manual delay to execute the next code but I want to make it dynamic. So, let me know how we can put dynamic delay based on the loader visible?
Code:
void main() {
group('App Test', () {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Login Fail Test', (WidgetTester tester) async {
await app.main();
await tester.pumpAndSettle();
await tester.pump(new Duration(seconds: 2));
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.pump(new Duration(seconds: 1));
await tester.enterText(passwordField, 'Test123');
await tester.pumpAndSettle();
await tester.pump(new Duration(seconds: 1));
await tester.tap(loginButton);
await tester.pumpAndSettle();
await tester.pump(new Duration(seconds: 3));
final dialog = find.byType(AlertDialog).first;
await tester.element(dialog);
await tester.pumpAndSettle();
await tester.pump(new Duration(seconds: 1));
final dialogButton = find.byType(FlatButton).first;
await tester.tap(dialogButton);
await tester.pumpAndSettle();
await tester.pump(new Duration(seconds: 2));
});
}
I have a file called utils.dart for functionality like this. In this case I use the following function which will basically poll until the finder is valid
// utils.dart
Future<void> pumpUntilFound(
WidgetTester tester,
Finder finder, {
Duration timeout = const Duration(seconds: 10),
}) async {
bool timerDone = false;
final timer = Timer(timeout, () => timerDone = true);
while (timerDone != true) {
await tester.pump();
final found = tester.any(finder);
if (found) {
timerDone = true;
}
}
timer.cancel();
}
You can also make it throw an exception if it times out, but the error messages aren't helpful, so I usually follow it up with an expect
It would look like
// my_test.dart
final fab = find.byKey(const ValueKey('fab'));
await pumpUntilFound(widgetTester, fab);
expect(fab, findsOneWidget);
Try wrapping like this:
testWidgets('test',
(WidgetTester tester) async {
await tester.runAsync(() async {
// test code here
});
});
If you use:
await tester.pumpAndSettle();
And then:
final widget = find.byKey(Key('whatever'));
It will find dinamically

Flutter integration_test - initialising and disposing dependencies

I’m initializing the app like
void main() async {
await Initializer.init();
runApp(MyApp());
}
Initializer.init() initializes all dependencies like Firebase Analytics and register things like Hive TypeAdapters.
My sample tests look like:
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets(
'Sample',
(WidgetTester tester) async {
await Initializer.init();
await tester.pumpWidget(MyApp());
await tester.tap(find.text('Something'));
expect(find.text('180 Results'), findsOneWidget);
},
);
testWidgets(
'Sample 2',
(WidgetTester tester) async {
await Initializer.init();
await tester.pumpWidget(MyApp());
await tester.tap(find.text('Something 2'));
expect(find.text('180 Results'), findsOneWidget);
},
);
}
My problem is that after executing the first test, things that were initialized by Initializer.init() aren’t disposed correctly.
Is there a way to tell integration_test to reset the whole environment every time test is reloaded?
Shall I initialize things differently than static Initializer.init();
Shall I explicitly dispose/unregister all dependencies (sth like Initializer.dispose() at the end of every test)? That solution seems to be a nightmare since I'm using many 3rd parties that are not allowing explicit disposing.

How to generate keyboard Event ENTER on a TextField in flutter_driver Tests

I am writing an integration test using flutter_driver for searching using text field I have to enter(Keyboard Event) after entering text, I cannot find any solution to generate keyboard event in flutter_Driver, is there any solution to this?
test('search tests, search a user by name', () async {
print('Waiting for join now button');
print('search test started');
await driver.clearTimeline();
print('pause for 5 sec');
await Future.delayed(Duration(seconds: 5));
print('Tapping search field');
await driver.waitFor(searchbar.searchFieldFinder);
await driver.tap(searchbar.searchFieldFinder);
print('enter user searching');
await driver.enterText('Test user');
//**Enter Keyboard Event here**
}, timeout: Timeout(Duration(minutes: 2)));
For keyboard event ENTER in integration tests you can use this code:
await tester.tap(find.byType(TextField));
await tester.enterText(find.byType(TextField), text);
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle(Duration(seconds: 1));
I don't know if it applies to driver tests, but in widget tests you can use the tester.sendKeyDownEvent() function like so:
await tester.sendKeyDownEvent(LogicalKeyboardKey.enter);
await tester.pumpAndSettle();
I would imagine that it would translate over to driver tests like this:
await driver.sendKeyDownEvent(LogicalKeyboardKey.enter);
await driver.pumpAndSettle();

Write Test for Flutter FutureBuilder

In my app after press button it's opening another screen, a form (StatefulWidget) which is loading from FutureBuilder. I need to write test class for this,
But in log it says when executing form is not finished build. This is test code,
await tester.tap(find.byIcon(Icons.add));
await tester.pump(const Duration(seconds: 1));
await tester.runAsync(() async {
when(tester.tap(find.byKey(Key("add_new_form")))).thenAnswer((_) => Future.delayed(Duration(seconds: 30), () => []));
await tester.pumpAndSettle(Duration(seconds: 10), EnginePhase.build, Duration(minutes: 1));
await tester.pump();
await tester.pump(const Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
expect(find.byKey(Key("form")), findsOneWidget);
});
how to write test class for flutter FutureBuilder ?? I have seen two questions relates to FutureBuilder but they are different from my situation. Any help would be appreciated.