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)));
}
Related
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);
});
I want to test a LongPressDraggable in Flutter.
The WidgetTester provide methods like longPress or several drag methods.
But there is no "longPressDrag" or something like this.
The first idea was to run a longPress and a drag. But after the longPress the widget tester doesnt hold the widget and i can't drag it.
await tester.longPress(from);
await tester.timedDrag(from, offset, Duration(milliseconds: time));
A workaround is to use the timedDrag and run it super slow.
This works but takes a lot of time.
await tester.timedDrag(from, offset, Duration(seconds: 15));
Is there a correct way to test the widget?
Use the startGesture method to start your own gesture. The "Finger is pressed" until you call geseture.up(). Between start and up use gesture.moveTo to move the cursor and tester.pump(duration) to stay still at a certain position to trigger the long-press.
Example code from the flutter repo in draggable_test.dart
final Offset firstLocation = tester.getCenter(find.text('Source'));
final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7);
await tester.pump();
expect(targetMoveCount['Target 1'], equals(0));
expect(targetMoveCount['Target 2'], equals(0));
final Offset secondLocation = tester.getCenter(find.text('Target 1'));
await gesture.moveTo(secondLocation);
await tester.pump();
expect(targetMoveCount['Target 1'], equals(1));
expect(targetMoveCount['Target 2'], equals(0));
final Offset thirdLocation = tester.getCenter(find.text('Target 2'));
await gesture.moveTo(thirdLocation);
await tester.pump();
expect(targetMoveCount['Target 1'], equals(1));
expect(targetMoveCount['Target 2'], equals(1));
await gesture.moveTo(secondLocation);
await tester.pump();
expect(targetMoveCount['Target 1'], equals(2));
expect(targetMoveCount['Target 2'], equals(1));
await gesture.up();
await tester.pump();
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
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);
});