diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md index 79eb13d61fad..6752386addb0 100644 --- a/packages/go_router/CHANGELOG.md +++ b/packages/go_router/CHANGELOG.md @@ -1,3 +1,9 @@ +## 17.3.1 + +- Fixes `popRoute()` crashing with `Bad state: No element` when + `currentConfiguration` is empty (e.g. during app startup before + the first route resolves). + ## 17.3.0 - Updates minimum supported SDK version to Flutter 3.38/Dart 3.10. diff --git a/packages/go_router/lib/src/delegate.dart b/packages/go_router/lib/src/delegate.dart index 1459d2f395ce..ee017c799f77 100644 --- a/packages/go_router/lib/src/delegate.dart +++ b/packages/go_router/lib/src/delegate.dart @@ -61,7 +61,9 @@ class GoRouterDelegate extends RouterDelegate with ChangeNotifie return true; // Return true if maybePop handled the pop } } - + if (currentConfiguration.isEmpty) { + return false; + } // Fallback to onExit if maybePop did not handle the pop final GoRoute lastRoute = currentConfiguration.last.route; if (lastRoute.onExit != null && navigatorKey.currentContext != null) { @@ -79,7 +81,7 @@ class GoRouterDelegate extends RouterDelegate with ChangeNotifie if (navigatorKey.currentState?.canPop() ?? false) { return true; } - if (currentConfiguration.matches.isEmpty) { + if (currentConfiguration.isEmpty) { return false; } RouteMatchBase walker = currentConfiguration.matches.last; @@ -115,7 +117,9 @@ class GoRouterDelegate extends RouterDelegate with ChangeNotifie // Set state directly without canPop check states.add(navigatorKey.currentState!); } - + if (currentConfiguration.isEmpty) { + return states.reversed; + } RouteMatchBase walker = currentConfiguration.matches.last; while (walker is ShellRouteMatch) { final NavigatorState potentialCandidate = walker.navigatorKey.currentState!; diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml index 77e1c11fde77..002dada9f39d 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: 17.3.0 +version: 17.3.1 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/delegate_test.dart b/packages/go_router/test/delegate_test.dart index 12d2d914ad6a..98cf1e87b1f6 100644 --- a/packages/go_router/test/delegate_test.dart +++ b/packages/go_router/test/delegate_test.dart @@ -345,6 +345,23 @@ void main() { }); }); + testWidgets('popRoute does not throw Bad state when currentConfiguration is empty', ( + WidgetTester tester, + ) async { + final GoRouter goRouter = GoRouter( + initialLocation: '/', + routes: [GoRoute(path: '/', builder: (_, _) => const DummyStatefulWidget())], + ); + addTearDown(goRouter.dispose); + await tester.pumpWidget(MaterialApp.router(routerConfig: goRouter)); + + // Simulate empty configuration (e.g. startup window before first route resolves) + goRouter.routerDelegate.currentConfiguration = RouteMatchList.empty; + + // Should return false without throwing "Bad state: No element" + expect(await goRouter.routerDelegate.popRoute(), isFalse); + }); + group('push', () { testWidgets('It should return different pageKey when push is called', ( WidgetTester tester,