How can I test that a AlertDialog appeared? - flutter

Hello I have a window with a button that should open an AlertDialog. How can I build a test that tells me that the alert opened?
var button = find.byKey(KEY_ADD_WALLET);
await tester.tap(button);
expect(... ??? ...)

I found the answer myself:
var button = find.byKey(KEY_ADD_WALLET);
await tester.tap(button);
await tester.pumpAndSettle();
expect(find.byType(Dialog), findsOneWidget);
The magic is calling tester.pumpAndSettle();
A more specific test could be:
expect(find.descendant(of: find.byType(Dialog), matching: find.text("Add public wallet")),findsOneWidget);

Related

Flutter Integration Test: How to wait until element is disappear with specific time out

I am writing a Flutter Integration Test and I'm looking for a code which that allows the automated test to run and proceed after the Login (check step below) finishes automatically.
.....
here are the step involves
Enter username and password
hit login button
then the loading modal will show up for 2 mins // at this step I need to find some code to make sure that the modal is disappeared so that it can proceed to the next step.
It's just like Wait Until Element Does Not Contain in Selenium
here is my code
await tester.pumpAndSettle();
await Future.delayed(const Duration(seconds: 4));
await tester.pumpAndSettle();
var textBoxForPhone = find.byKey(const Key('txtbPhone'));
var textBoxForPass = find.byKey(const Key('txtbPass'));
var btnLogin = find.byKey(const Key('btnLogin'));
var syncMasterModal = find.byKey(const Key('syncMasterModal'));
// Input Username
await tester.enterText(textBoxForPhone, '9108717875');
// Input Password
await tester.enterText(textBoxForPass, '12345');
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pumpAndSettle();
// Tap Login button
await tester.tap(btnLogin);
//After tapping the login button the loading modal will appear and it takes about 2 minutes to finish this process
// So it is at this step where I need the code to detect whether the loading modal is disappear
So could you guys help point me in the right direction?
PS. This is my first time here and English is not my first language so, I'm sorry if my text here is a bit confusing.
after -> await tester.tap(btnLogin);
try to add the following lines
await tester.pumpAndSettle();
await tester.pumpAndSettle(const Duration(minutes: 2)); // hardcode it if you are sure about the needed time
expect(find.byType(YourModalWidget), findsNothing);
continue with other code...
Tip: in your tests, when you are transitioning from one screen to the next, after the first pumpAndSettle() add another with a Duration of around 1 second, or 200/500 milliseconds (depends on what you are expecting to load, and tap after that). This will make the transition much smoother and it won't look like it is frozen. if you only add pumpAndSettle(const Duration(seconds: 1)), without the first pumpAndSettle() before it, it looks like it's frozen and then the next action in your tests starts.

Integration tests work fine from flutter drive, but hang when entering text in Firebase Test Lab

I have the following sign-in test set up for my app:
testWidgets('sign in with email and password', (WidgetTester tester) async {
app.main();
await tester.pumpAndSettle(Duration(seconds: 3));
final emailInputFinder = find.byKey(Key('type-email'));
final passwordInputFinder = find.byKey(Key('type-password'));
final emailButtonFinder = find.byKey(Key('enter-email'));
final passwordButtonFinder = find.byKey(Key('enter-password'));
final dashboardFinder = find.byKey(Key('dashboard'));
await tester.enterText(emailInputFinder, 'test.lab.user.01#...');
await tester.pumpAndSettle(Duration(seconds: 3));
await tester.tap(emailButtonFinder);
await tester.pumpAndSettle(Duration(seconds: 3));
await tester.enterText(passwordInputFinder, '...');
await tester.pumpAndSettle(Duration(seconds: 3));
await tester.tap(passwordButtonFinder);
await tester.pumpAndSettle(Duration(seconds: 3));
expect(dashboardFinder, findsOneWidget);
});
The hardcoded 3 second delay isn't ideal, but without it I can't run the tests using the driver.
Running on my local machine with the driver is fine. I use the command
flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart
But when I upload the Espresso test to Firebase Test Lab and review the video, the sign-in screen loads up, but the first enterText() command seems to have no effect. Nothing is added to the text field, and the test just times out.
I have tried various combinations of tester.tap() and tester.showKeyboard(), but so far, nothing is coming up.
How can I get enterText() to work correctly in the Espresso environment supported by TestLab?
Try calling binding.testTextInput.register():
final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
// Necessary for being able to enterText when not in debug mode
binding.testTextInput.register();
There is an issue in the flutter repo about documenting this. Basically if you're not in debug mode you have to call binding.testTextInput.register() in order for tester.enterText to work.

Flutter integration test for UI and HTTP call

I have a simple login screen that calls login API and I trying to wait for the second screen after ProgressIndicator finishes and the new screen comes.
But It shows loading ProgressIndicator then it never goes to the second screen and expects function fails
So what should I do or what is similar to waitFor but for Flutter integration_test library?
My testing code
await tester.tap(find.byKey(const Key('loginButton')));
await tester.pumpAndSettle();
await tester.ensureVisible(find.byKey(const Key('loadingWidget')));
await tester.pumpAndSettle();
await tester.ensureVisible(find.byType(DetailsScreen));
expect(find.text('Log In'), findsNothing);
Here is the login button onTap
BlocProvider.of<LoginBloc>(context).add(
LoginEvent.loginWithEmail(
email: emailController.text,
password: passwordController.text,
),
);
You should use pumpAndSettle method of WidgetTester to wait until animations end. Your code will be like this:
testWidgets("Login test", (tester) async {
...
await tester.tap(find.byKey(ValueKey('Login')));
await tester.pumpAndSettle();
...
}
My goal is integration test so I replaced integration_test with the default Flutter driver and I was able to waitFor while animation by using
await driver.runUnsynchronized(() async {
//wait for something
});
More info: https://github.com/flutter/flutter/issues/36244
And I mock my Dio HTTP client by the following library
http_mock_adapter

widget test, testing a button with CircularProgressIndicator

I have two tests that after a click on a button I want to test if a CircularProgressIndicator will appear on the button.
The problem is after the tap and the tester.pump(), it can't find the CircularProgressIndicator causing the test to fail, I tried with pumpAndSettle() and also add a Duration(seconds:x) but got the same error
It's weird because the tests were ok before I update the flutter sdk to 1.22.0, upgrade my flutterFire packages and migrate to use the Android embbeding V2.
testWidgets("Should show loading button when click on request button ",
(WidgetTester tester) async {
await tester.pumpWidget(
_buildWidget(
home: FinancialDialogBill(
paymentId: "fakePaymentId",
additionalValueType: AdditionalValueType.fee,
billValues: billValues,
installmentList: installments,
),
),
);
expect(find.byKey(financialDialogBillRequestButton), findsOneWidget);
expect(find.byKey(financialDialogBillRequestButtonLoading), findsNothing);
await tester.tap(find.byKey(financialDialogBillRequestButton));
await tester.pump();
expect(
find.byKey(financialDialogBillRequestButtonLoading), findsOneWidget);
expect(find.byKey(financialDialogBillRequestButton), findsNothing);
});
});
A bit late, but i ran into this issue as well, the shortest workaround i found i just to try/catch the timeout error...
try {
await tester.pumpAndSettle();
} catch (err) {}
expect(find.byKey(financialDialogBillRequestButtonLoading), findsOneWidget);
expect(find.byKey(financialDialogBillRequestButton), findsNothing);
Happy if it can help someone before a better solution is found.

Returning value printed by button during Flutter integration test?

I have a simple app that has a screen with a button. When this button is pressed the login screen pops up; It has two text fields (one for email and one for password), and a button. When the button is pressed, the credentials are authenticated and the json containing the info is printed to the console (I haven't implemented the whole functionality of the button yet since this will take a long time).
I'm running a group of integration tests to see if the app runs normally, which includes having the json printed to the console. That, however, doesn't happen, but it does when I debug the app. Is there any way to print that json to the console during an integration test?
These are my tests:
test('Button renders', () async {
expect(await driver.getText(enterTextFinder), "Enter");
});
test('Button taps', () async {
await driver.tap(enterButtonFinder);
expect(await driver.getText(acceptTextFinder), "Accept");
});
test('Enter credentials', () async {
await driver.tap(emailFieldFinder);
await driver.enterText(email);
await driver.tap(passFieldFinder);
await driver.enterText(password);
});
test('Perform login', () async {
await driver.tap(acceptButtonFinder);
});