Scenario
I am new to widget testing and GoRouter. I have a very simple test case:
- There are two screens –
LoginPage
which loads as the first screen, and aCheckoutPage
LoginPage
has a button. Once I tap on it, I’m being taken to theCheckoutPage
.
I am using GoRouter for my navigation.
Code
Here is how the MaterialApp
is set up in main.dart:
MaterialApp.router(
debugShowCheckedModeBanner: false,
routerConfig: GoRouteInformation.router,
title: "Neon Student",
),
Here are the routerConfig
and RouteNames
classes:
RouterConfig
class GoRouteInformation {
static final GoRouter router = GoRouter(
routes: [
GoRoute(
path: "https://stackoverflow.com/",
name: RouteNames.login,
builder: (context, state) => const LoginPage(),
routes: [
GoRoute(
path: 'checkout',
name: RouteNames.checkout,
builder: (context, state) => const CheckoutPage(),
),
],
),
],
);
}
RouteNames
class RouteNames {
static const String login = 'login';
static const String checkout="checkout";
}
The following is the code in loginpage_test.dart:
testWidgets('Navigates from LoginPage to CheckoutPage', (WidgetTester tester) async {
await tester.pumpWidget(const MainApp());
await tester.pumpWidget(const MaterialApp(home: LoginPage()));
expect(find.byType(LoginSection), findsOneWidget);
expect(find.byType(SplitDivider), findsOneWidget);
Finder subscribeButton = find.byKey(const ValueKey('Subscribe'));
expect(subscribeButton, findsOneWidget);
await tester.tap(subscribeButton);
await tester.pumpAndSettle();
expect(find.byType(CheckoutPage), findsOneWidget);
});
EDIT: Here is my main.dart
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: const Size(428, 926),
minTextAdapt: true,
splitScreenMode: true,
builder: (_, child) {
return GestureDetector(
onTap: () {
FocusManager.instance.primaryFocus?.unfocus();
},
behavior: HitTestBehavior.opaque,
child: MaterialApp.router(
debugShowCheckedModeBanner: false,
routerConfig: GoRouteInformation.router,
title: "Neon Student",
),
);
},
);
}
}
Problem
When I run flutter test, I get the following error:
- The following assertion was thrown while handling a gesture:
No GoRouter found in context
‘package:go_router/src/router.dart’:
Failed assertion: line 507 pos 12: ‘inherited != null’ - The following TestFailure was thrown running a test:
Expected: exactly one matching candidate
Actual: _TypeWidgetFinder:<Found 0 widgets with type “CheckoutPage”: []>
Which: means none were found but one was expected
Request
I would like to know what is wrong in my widget test code which is causing the test to fail and how to rectify it.
await tester.pumpWidget(const MainApp());
await tester.pumpWidget(const MaterialApp(home: LoginPage()));
This is the problematic part. It has two problems:
- This first pump is basically ignored, because you pump another widget. You can have only one widget present in the “sandbox” at a given moment.
- You pump a bare-boned
MaterialApp
, without the routing.
To have the router available in your tests, you must pass it to the pumped app just like you do in MainApp
:
await tester.pumpWidget(
MaterialApp.router(
routerConfig: GoRouteInformation.router,
home: const LoginPage(),
),
);
You can make a utility widget TestApp
in your test/
directory that would be reused in your widget tests that will have all the surroundings needed for the widgets to function properly.
This explains the error you are getting:
The following assertion was thrown while handling a gesture: No GoRouter found in context ‘package:go_router/src/router.dart’: Failed assertion: line 507 pos 12: ‘inherited != null’
It means that GoRouter.of(context)
couldn’t find the router in the widget tree above your LoginPage
. This is because your MaterialApp
from the pump didn’t have that router.
Could you share the full code of your main file?
@AlvaroDosio I have edited my post to add main.dart contents