Test onTap behaviour - flutter

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);
});

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);
});

The following assertion was thrown while running async test code: pumpAndSettle timed out

In flutter test i have error:
The following assertion was thrown while running async test code:pumpAndSettle timed out
My test script:
testWidgets('drawer widget test', (WidgetTester tester) async {
TestWidgetsFlutterBinding.ensureInitialized();
await tester.runAsync(() async {
when(operatorRepository.getCurrentSelectedOperator()).thenAnswer((_) async => operator);
await tester.pumpWidget(MaterialApp(home: ScaffoldDrawerTest(operatorRepository)));
expect(find.text('-1'), findsOneWidget);
expect(find.text(''), findsOneWidget);
expect(find.text('Warszawa'), findsNothing);
await tester.tap(find.byType(IconButton).first);
await tester.pumpAndSettle();
expect(find.text('Warszawa'), findsWidgets);
await tester.pumpAndSettle();
await tester.tap(find.byType(ListTile).at(2));
expect(find.text('Warszawa'), findsNothing);
});
});
I try change pumpAndSettle to for (int i = 0; i < 5; i++) { await tester.pump(Duration(seconds: 1)); }
but then i to receive error
Actual: _TextFinder:<zero widgets with text "Warszawa" (ignoring offstage widgets)>
Which: means none were found but some were expected
In ScaffoldDrawerTest i have Consumer and loading widget, when viewModel is loaded then i show another widgets when is widget text "Warszawa"

The following assertion was thrown running a test: pumpAndSettle timed out

here is a test case which test if i failded to add data to my database it will show
error message in snackbar but my test showing pumpAndSettle timed out error
testWidgets(
'renders error snack bar '
'when status changes to failure', (tester) async {
whenListen<TodosOverviewState>(
todosOverviewBloc,
Stream.fromIterable([
const TodosOverviewState(),
const TodosOverviewState(status: TodosOverviewStatus.failure)
]));
await tester.pumpApp(buildSubject(), todosRepository: todosRepository);
await tester.pumpAndSettle();
expect(find.byType(SnackBar), findsOneWidget);
expect(
find.descendant(
of: find.byType(SnackBar),
matching: find.text('todo status failed')),
findsOneWidget);
});
Error:
remove await tester.pumpAndSettle();
and put await tester.pump();

Tap() in widget test showing warning in flutter

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)));
}

Flutter widget test - wait Future completion

I have a widget test in flutter that pumps the widget under test,
and when it opens, performs a background operation (staticWrapper.requestPermission()) which returns a Future and, based on its result, set a state.
The problem is that the test is not waiting this future to complete, test code:
/// When micro permission denied, should show error message.
testWidgets('When micro permission denied, should show error message.',
(WidgetTester tester) async {
when(staticWrapper.requestPermission(Permission.RecordAudio))
.thenAnswer((_) => Future.value(PermissionStatus.denied));
await tester.pumpWidget(widget);
final loginText = find.text(callScreen_microPermissionDenied);
expect(loginText, findsOneWidget);
});
Affected widget code:
void _requestMicroPermission() async {
final result =
await staticWrapper.requestPermission(Permission.RecordAudio);
debugPrint("Microphone permission status: $result");
if (result == PermissionStatus.authorized) {
native.init();
} else {
setState(() {
_loginText = tnsManager.getText(TranslationsManager.callScreen_microPermissionDenied);
});
}
}
The expect() method is called before the setState() call.
Any help?
Finally I solved the issue using WidgetTester#pumpAndSettle():
testWidgets('When micro permission denied, should show error message.',
(WidgetTester tester) async {
when(staticWrapper.requestPermission(Permission.RecordAudio))
.thenAnswer((_) => Future.value(PermissionStatus.denied));
await tester.pumpWidget(widget);
await tester.pump();
final loginText = find.text(callScreen_microPermissionDenied);
expect(loginText, findsOneWidget);
});