How to mock navigation arguments for testing flutter screen widgets?
Solution 1
The way that I've found is the same approach how flutter guys are testing it: https://github.com/flutter/flutter/blob/d03aecab58f5f8b57a8cae4cf2fecba931f60673/packages/flutter/test/widgets/navigator_test.dart#L715
Basically they create a MaterialApp
, put a button that after pressing will navigate to the tested page.
My modified solution:
Future<void> pumpArgumentWidget(
WidgetTester tester, {
@required Object args,
@required Widget child,
}) async {
final key = GlobalKey<NavigatorState>();
await tester.pumpWidget(
MaterialApp(
navigatorKey: key,
home: FlatButton(
onPressed: () => key.currentState.push(
MaterialPageRoute<void>(
settings: RouteSettings(arguments: args),
builder: (_) => child,
),
),
child: const SizedBox(),
),
),
);
await tester.tap(find.byType(FlatButton));
await tester.pumpAndSettle(); // Might need to be removed when testing infinite animations
}
This approach works ok-ish, had some issues with testing progress indicators as it was not able to find those even when debugDumpApp
displayed them.
Solution 2
If you are using a Dependency Injector such as I am, you may need to avoid pass contextual arguments to the constructor if your view is not built at the time the view class is instantiated. Otherwise, just use the view constructor as someone suggested.
So if you can't use constructor as I can't, you can solve this using Navigator directly in your tests. Navigator is a widget, so just use it to return your screen. Btw, it has no problem with Progress Indicator as pointed above.
import 'package:commons/core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
class MyCustomArgumentsMock extends Mock implements MyCustomArguments {}
void main() {
testWidgets('indicator is shown when screen is opened', (tester) async {
final MyCustomArguments mock = MyCustomArgumentsMock();
await tester.pumpWidget(MaterialApp(
home: Navigator(
onGenerateRoute: (_) {
return MaterialPageRoute<Widget>(
builder: (_) => TestScreen(),
settings: RouteSettings(arguments: mock),
);
},
),
));
expect(find.byType(CircularProgressIndicator), findsOneWidget);
});
}
![Daniel](https://i.stack.imgur.com/SbpEL.jpg?s=256&g=1)
Daniel
I am the administrator of ElderScrollsPortal.de and I'm working at OPITZ CONSULTING. In my free time, I also develop smaller projects.
Updated on December 12, 2022Comments
-
Daniel over 1 year
I would like to write a mockito test for a screen widget in flutter. The problem is, that this widget uses a variable from the navigation argument and I'm not sure how to mock this variable.
This is the example screen:
class TestScreen extends StatefulWidget { static final routeName = Strings.contact; @override _TestScreenState createState() => _TestScreenState(); } class _TestScreenState extends State<TestScreen> { Contact _contact; @override Widget build(BuildContext context) { _contact = ModalRoute.of(context).settings.arguments; return Scaffold( appBar: AppBar(title: Text(Strings.contact)), body: Text(_contact.name), ); } }
With this command I open the screen
Navigator.pushNamed(context, TestScreen.routeName, arguments: contact);
Normally I would mock some components, but I'm not sure how to mock the screen arguments. I hope it works something like this. However, I do not know what I can exactly mock.
when(screenArgument.fetchData(any)) .thenAnswer((_) async => expectedContact);
This is the current test, which of course is not working since _contact is null:
void main() { testWidgets('contact fields should be filled with data from argument', (WidgetTester tester) async { // GIVEN final testScreen = TestApp(widget: TestScreen()); // WHEN await tester.pumpWidget(testScreen); // THEN expect(find.text("test"), findsOneWidget); }); }
An ugly way would be to use constructor parameters for the screen only for testing, but I want to avoid that.
Maybe someone of you knows how to best test such screen widgets.
-
X09 about 4 yearsPlease, did you solve the issue of progress indicator?