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);
});
Related
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
Hi I'm trying to verify mockObserver to check push to other screen. But when didPush(any,any), it's show err from type any.
I'm using mockito: ^5.0.13
(tester) async {
await tester.pumpWidget(widget);
await tester.tap(find.widgetWithText(TextButton, 'Join with us'));
await tester.pumpAndSettle();
verify(mockObserver.didPush(any, any));
});
await widgetTester.tap(find.byType(ElevatedButton));
shows warning :
Maybe the widget is actually off-screen, or another widget is obscuring it, or the widget cannot receive pointer events.
Try this:
await widgetTester.ensureVisible(find.byType(ElevatedButton));
await widgetTester.pumpAndSettle();
await widgetTester.tap(find.byType(ElevatedButton));
I just replace await tester.pump(); by await tester.pumpAndSettle(); before tap
It works for me.
I suggest creating a safeTapBy function logic. This just ensures that the button is visible (keyboard showing, off screen etc). Here is an example using find.byKey:
Future safeTapByKey(WidgetTester tester, String key) async {
await tester.ensureVisible(find.byKey(Key(key)));
await tester.pumpAndSettle();
await tester.tap(find.byKey(Key(key)));
}
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();
I would like to test that when I am tapping a button, the user is routed to the next page. This works in the UI. I introduced the test but I get the following error:
The following TestFailure object was thrown running a test: Expected: exactly one matching node in the widget tree Actual: _WidgetTypeFinder:<zero widgets with type "MyNextView" (ignoring offstage widgets)> Which: means none were found but one was expected
What am I doing wrong?
testWidgets('Button tap routes to next page', (WidgetTester tester) async {
final button = createButton();
await tester.pumpWidget(button);
await tester.tap(find.byWidget(button));
expect(find.byType(MyNextView), findsOneWidget);
});
After >
await tester.tap(find.byWidget(button));
Put this line >
await tester.pumpAndSettle(); // Wait for screen to update
testWidgets('Button tap routes to next page', (WidgetTester tester) async {
final button = createButton();
await tester.pumpWidget(button);
await tester.tap(find.byWidget(button));
await tester.pumpAndSettle(); // Wait for screen to update
expect(find.byType(MyNextView), findsOneWidget);
});