[go_router] Fix parentNavigatorKey not working with multiple nested Routes in ShellRoute (#2784)
* [go_router] Fix parentNavigatorKey with multiple nested Routes in ShellRoute (#111961)
* Update packages/go_router/CHANGELOG.md
Co-authored-by: chunhtai <47866232+chunhtai@users.noreply.github.com>
Co-authored-by: chunhtai <47866232+chunhtai@users.noreply.github.com>
diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md
index 186fabb..146368b 100644
--- a/packages/go_router/CHANGELOG.md
+++ b/packages/go_router/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 5.1.6
+
+- Fixes crashes when multiple `GoRoute`s use the same `parentNavigatorKey` in a route subtree.
+
## 5.1.5
- Adds migration guide for 5.1.2 to readme.
diff --git a/packages/go_router/lib/src/configuration.dart b/packages/go_router/lib/src/configuration.dart
index fa7261b..8f97a7c 100644
--- a/packages/go_router/lib/src/configuration.dart
+++ b/packages/go_router/lib/src/configuration.dart
@@ -60,9 +60,9 @@
checkParentNavigatorKeys(
route.routes,
<GlobalKey<NavigatorState>>[
- // Once a parentNavigatorKey is used, only the navigator keys
- // above it can be used.
- ...allowedKeys.sublist(0, allowedKeys.indexOf(parentKey)),
+ // Once a parentNavigatorKey is used, only that navigator key
+ // or keys above it can be used.
+ ...allowedKeys.sublist(0, allowedKeys.indexOf(parentKey) + 1),
],
);
} else {
diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml
index 3973a2a..94df1c9 100644
--- a/packages/go_router/pubspec.yaml
+++ b/packages/go_router/pubspec.yaml
@@ -1,7 +1,7 @@
name: go_router
description: A declarative router for Flutter based on Navigation 2 supporting
deep linking, data-driven routes and more
-version: 5.1.5
+version: 5.1.6
repository: https://github.com/flutter/packages/tree/main/packages/go_router
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22
diff --git a/packages/go_router/test/configuration_test.dart b/packages/go_router/test/configuration_test.dart
index 61f769f..3536531 100644
--- a/packages/go_router/test/configuration_test.dart
+++ b/packages/go_router/test/configuration_test.dart
@@ -176,6 +176,55 @@
);
test(
+ 'Does not throw with multiple nested GoRoutes using parentNavigatorKey in ShellRoute',
+ () {
+ final GlobalKey<NavigatorState> root =
+ GlobalKey<NavigatorState>(debugLabel: 'root');
+ final GlobalKey<NavigatorState> shell =
+ GlobalKey<NavigatorState>(debugLabel: 'shell');
+ RouteConfiguration(
+ navigatorKey: root,
+ routes: <RouteBase>[
+ ShellRoute(
+ navigatorKey: shell,
+ routes: <RouteBase>[
+ GoRoute(
+ path: '/',
+ builder: _mockScreenBuilder,
+ routes: <RouteBase>[
+ GoRoute(
+ path: 'a',
+ builder: _mockScreenBuilder,
+ parentNavigatorKey: root,
+ routes: <RouteBase>[
+ GoRoute(
+ path: 'b',
+ builder: _mockScreenBuilder,
+ parentNavigatorKey: root,
+ routes: <RouteBase>[
+ GoRoute(
+ path: 'c',
+ builder: _mockScreenBuilder,
+ parentNavigatorKey: root,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ ],
+ redirectLimit: 10,
+ topRedirect: (BuildContext context, GoRouterState state) {
+ return null;
+ },
+ );
+ },
+ );
+
+ test(
'Throws when parentNavigatorKeys are overlapping',
() {
final GlobalKey<NavigatorState> root =
@@ -369,78 +418,50 @@
navigatorKey: root,
);
});
- });
- test(
- 'Does not throw with valid parentNavigatorKey configuration',
- () {
- final GlobalKey<NavigatorState> root =
- GlobalKey<NavigatorState>(debugLabel: 'root');
- final GlobalKey<NavigatorState> shell =
- GlobalKey<NavigatorState>(debugLabel: 'shell');
- final GlobalKey<NavigatorState> shell2 =
- GlobalKey<NavigatorState>(debugLabel: 'shell2');
- RouteConfiguration(
- navigatorKey: root,
- routes: <RouteBase>[
- ShellRoute(
- navigatorKey: shell,
- routes: <RouteBase>[
- GoRoute(
- path: '/',
- builder: _mockScreenBuilder,
- routes: <RouteBase>[
- GoRoute(
- path: 'a',
- builder: _mockScreenBuilder,
- parentNavigatorKey: root,
- routes: <RouteBase>[
- ShellRoute(
- navigatorKey: shell2,
- routes: <RouteBase>[
- GoRoute(
- path: 'b',
- builder: _mockScreenBuilder,
- routes: <RouteBase>[
- GoRoute(
- path: 'b',
- builder: _mockScreenBuilder,
- parentNavigatorKey: shell2,
- ),
- ],
- ),
- ],
- ),
- ],
- ),
- ],
- ),
- ],
- ),
- ],
- redirectLimit: 10,
- topRedirect: (BuildContext context, GoRouterState state) {
- return null;
- },
- );
- },
- );
-
- test('throws when ShellRoute contains a GoRoute with a parentNavigatorKey',
+ test(
+ 'Does not throw with valid parentNavigatorKey configuration',
() {
- final GlobalKey<NavigatorState> root =
- GlobalKey<NavigatorState>(debugLabel: 'root');
- expect(
- () {
+ final GlobalKey<NavigatorState> root =
+ GlobalKey<NavigatorState>(debugLabel: 'root');
+ final GlobalKey<NavigatorState> shell =
+ GlobalKey<NavigatorState>(debugLabel: 'shell');
+ final GlobalKey<NavigatorState> shell2 =
+ GlobalKey<NavigatorState>(debugLabel: 'shell2');
RouteConfiguration(
navigatorKey: root,
routes: <RouteBase>[
ShellRoute(
+ navigatorKey: shell,
routes: <RouteBase>[
GoRoute(
- path: '/a',
+ path: '/',
builder: _mockScreenBuilder,
- parentNavigatorKey: root,
+ routes: <RouteBase>[
+ GoRoute(
+ path: 'a',
+ builder: _mockScreenBuilder,
+ parentNavigatorKey: root,
+ routes: <RouteBase>[
+ ShellRoute(
+ navigatorKey: shell2,
+ routes: <RouteBase>[
+ GoRoute(
+ path: 'b',
+ builder: _mockScreenBuilder,
+ routes: <RouteBase>[
+ GoRoute(
+ path: 'b',
+ builder: _mockScreenBuilder,
+ parentNavigatorKey: shell2,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ],
+ ),
+ ],
),
],
),
@@ -451,8 +472,36 @@
},
);
},
- throwsAssertionError,
);
+
+ test('throws when ShellRoute contains a GoRoute with a parentNavigatorKey',
+ () {
+ final GlobalKey<NavigatorState> root =
+ GlobalKey<NavigatorState>(debugLabel: 'root');
+ expect(
+ () {
+ RouteConfiguration(
+ navigatorKey: root,
+ routes: <RouteBase>[
+ ShellRoute(
+ routes: <RouteBase>[
+ GoRoute(
+ path: '/a',
+ builder: _mockScreenBuilder,
+ parentNavigatorKey: root,
+ ),
+ ],
+ ),
+ ],
+ redirectLimit: 10,
+ topRedirect: (BuildContext context, GoRouterState state) {
+ return null;
+ },
+ );
+ },
+ throwsAssertionError,
+ );
+ });
});
}