From 5cea2f7e7a5a3550a6f990de709ce489ace02f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Sasovsky?= Date: Wed, 30 Jul 2025 16:47:28 -0300 Subject: [PATCH 01/10] feat: access GoRouter.of from redirect methods --- packages/go_router/lib/src/configuration.dart | 57 ++++++++++++------- .../go_router/lib/src/misc/extensions.dart | 2 - packages/go_router/lib/src/router.dart | 30 ++++++++-- packages/go_router/test/go_router_test.dart | 55 ++++++++++++++++++ 4 files changed, 117 insertions(+), 27 deletions(-) diff --git a/packages/go_router/lib/src/configuration.dart b/packages/go_router/lib/src/configuration.dart index a730500b6b0..38652ec9b2d 100644 --- a/packages/go_router/lib/src/configuration.dart +++ b/packages/go_router/lib/src/configuration.dart @@ -16,6 +16,9 @@ import 'route.dart'; import 'router.dart'; import 'state.dart'; +/// Symbol used as a Zone key to track the current GoRouter during redirects. +const Symbol _currentRouterKey = #goRouterRedirectContext; + /// The signature of the redirect callback. typedef GoRouterRedirect = FutureOr Function( BuildContext context, GoRouterState state); @@ -29,6 +32,7 @@ class RouteConfiguration { this._routingConfig, { required this.navigatorKey, this.extraCodec, + this.router, }) { _onRoutingTableChanged(); _routingConfig.addListener(_onRoutingTableChanged); @@ -232,22 +236,17 @@ class RouteConfiguration { /// The limit for the number of consecutive redirects. int get redirectLimit => _routingConfig.value.redirectLimit; - /// The global key for top level navigator. + /// The global key for the root navigator. final GlobalKey navigatorKey; - /// The codec used to encode and decode extra into a serializable format. - /// - /// When navigating using [GoRouter.go] or [GoRouter.push], one can provide - /// an `extra` parameter along with it. If the extra contains complex data, - /// consider provide a codec for serializing and deserializing the extra data. - /// - /// See also: - /// * [Navigation](https://pub.dev/documentation/go_router/latest/topics/Navigation-topic.html) - /// topic. - /// * [extra_codec](https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/extra_codec.dart) - /// example. + /// The codec used to encode and decode the extra parameter. See + /// [GoRoute.builder] and [GoRoute.pageBuilder] for more info. final Codec? extraCodec; + /// The GoRouter instance that owns this configuration. + /// This is used to provide access to the router during redirects. + final GoRouter? router; + final Map _nameToPath = {}; /// Looks up the url location by a [GoRoute]'s name. @@ -416,10 +415,12 @@ class RouteConfiguration { redirectHistory.add(prevMatchList); // Check for top-level redirect - final FutureOr topRedirectResult = _routingConfig.value.redirect( - context, - buildTopLevelGoRouterState(prevMatchList), - ); + final FutureOr topRedirectResult = _runInRouterZone(() { + return _routingConfig.value.redirect( + context, + buildTopLevelGoRouterState(prevMatchList), + ); + }); if (topRedirectResult is String?) { return processTopLevelRedirect(topRedirectResult); @@ -448,10 +449,12 @@ class RouteConfiguration { _getRouteLevelRedirect( context, matchList, routeMatches, currentCheckIndex + 1); final RouteBase route = match.route; - final FutureOr routeRedirectResult = route.redirect!.call( - context, - match.buildState(this, matchList), - ); + final FutureOr routeRedirectResult = _runInRouterZone(() { + return route.redirect!.call( + context, + match.buildState(this, matchList), + ); + }); if (routeRedirectResult is String?) { return processRouteRedirect(routeRedirectResult); } @@ -508,6 +511,20 @@ class RouteConfiguration { .join(' => '); } + /// Runs the given function in a Zone with the router context for redirects. + T _runInRouterZone(T Function() callback) { + if (router == null) { + return callback(); + } + + return runZoned( + callback, + zoneValues: { + _currentRouterKey: router, + }, + ); + } + /// Get the location for the provided route. /// /// Builds the absolute path for the route, by concatenating the paths of the diff --git a/packages/go_router/lib/src/misc/extensions.dart b/packages/go_router/lib/src/misc/extensions.dart index 3c390c94598..f8cca2249d3 100644 --- a/packages/go_router/lib/src/misc/extensions.dart +++ b/packages/go_router/lib/src/misc/extensions.dart @@ -10,8 +10,6 @@ import '../router.dart'; /// context.go('/'); extension GoRouterHelper on BuildContext { /// Get a location from route name and parameters. - /// - /// This method can't be called during redirects. String namedLocation( String name, { Map pathParameters = const {}, diff --git a/packages/go_router/lib/src/router.dart b/packages/go_router/lib/src/router.dart index 9962dd2d449..31e8fa3ef4d 100644 --- a/packages/go_router/lib/src/router.dart +++ b/packages/go_router/lib/src/router.dart @@ -18,6 +18,9 @@ import 'parser.dart'; import 'route.dart'; import 'state.dart'; +/// Symbol used as a Zone key to track the current GoRouter during redirects. +const Symbol _currentRouterKey = #goRouterRedirectContext; + /// The function signature of [GoRouter.onException]. /// /// Use `state.error` to access the exception. @@ -206,6 +209,7 @@ class GoRouter implements RouterConfig { _routingConfig, navigatorKey: navigatorKey, extraCodec: extraCodec, + router: this, ); final ParserExceptionHandler? parserExceptionHandler; @@ -519,21 +523,37 @@ class GoRouter implements RouterConfig { /// Find the current GoRouter in the widget tree. /// - /// This method throws when it is called during redirects. + /// This method can now be called during redirects. static GoRouter of(BuildContext context) { final GoRouter? inherited = maybeOf(context); - assert(inherited != null, 'No GoRouter found in context'); - return inherited!; + if (inherited != null) { + return inherited; + } + + // Check if we're in a redirect context + final GoRouter? redirectRouter = + Zone.current[_currentRouterKey] as GoRouter?; + if (redirectRouter != null) { + return redirectRouter; + } + + throw FlutterError('No GoRouter found in context'); } /// The current GoRouter in the widget tree, if any. /// - /// This method returns null when it is called during redirects. + /// This method can now return a router even during redirects. static GoRouter? maybeOf(BuildContext context) { final InheritedGoRouter? inherited = context .getElementForInheritedWidgetOfExactType() ?.widget as InheritedGoRouter?; - return inherited?.goRouter; + + if (inherited != null) { + return inherited.goRouter; + } + + // Check if we're in a redirect context + return Zone.current[_currentRouterKey] as GoRouter?; } /// Disposes resource created by this object. diff --git a/packages/go_router/test/go_router_test.dart b/packages/go_router/test/go_router_test.dart index 5d6b142c313..e8d27639d08 100644 --- a/packages/go_router/test/go_router_test.dart +++ b/packages/go_router/test/go_router_test.dart @@ -2238,6 +2238,61 @@ void main() { expect(redirected, isTrue); }); + testWidgets('GoRouter.of(context) should work in redirects', + (WidgetTester tester) async { + GoRouter? capturedRouter; + final List routes = [ + GoRoute( + path: '/', + builder: (BuildContext context, GoRouterState state) => + const HomeScreen(), + ), + GoRoute( + path: '/login', + builder: (BuildContext context, GoRouterState state) => + const LoginScreen(), + ), + ]; + + final GoRouter router = await createRouter(routes, tester, + redirect: (BuildContext context, GoRouterState state) { + // This should not throw an exception + capturedRouter = GoRouter.of(context); + return state.matchedLocation == '/login' ? null : '/login'; + }); + + expect(capturedRouter, isNotNull); + expect(capturedRouter, equals(router)); + }); + + testWidgets('Context extension methods should work in redirects', + (WidgetTester tester) async { + String? capturedNamedLocation; + final List routes = [ + GoRoute( + path: '/', + name: 'home', + builder: (BuildContext context, GoRouterState state) => + const HomeScreen(), + ), + GoRoute( + path: '/login', + name: 'login', + builder: (BuildContext context, GoRouterState state) => + const LoginScreen(), + ), + ]; + + await createRouter(routes, tester, + redirect: (BuildContext context, GoRouterState state) { + // This should not throw an exception + capturedNamedLocation = context.namedLocation('login'); + return state.matchedLocation == '/login' ? null : '/login'; + }); + + expect(capturedNamedLocation, '/login'); + }); + testWidgets('redirect can redirect to same path', (WidgetTester tester) async { final List routes = [ From 05b94b72b92d981f5acceef1cf43771cbd048332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Sasovsky?= Date: Wed, 30 Jul 2025 16:54:34 -0300 Subject: [PATCH 02/10] refactor: update documentation for navigatorKey and extraCodec in RouteConfiguration --- packages/go_router/lib/src/configuration.dart | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/go_router/lib/src/configuration.dart b/packages/go_router/lib/src/configuration.dart index 38652ec9b2d..2293e88b37e 100644 --- a/packages/go_router/lib/src/configuration.dart +++ b/packages/go_router/lib/src/configuration.dart @@ -236,11 +236,20 @@ class RouteConfiguration { /// The limit for the number of consecutive redirects. int get redirectLimit => _routingConfig.value.redirectLimit; - /// The global key for the root navigator. + /// The global key for top level navigator. final GlobalKey navigatorKey; - /// The codec used to encode and decode the extra parameter. See - /// [GoRoute.builder] and [GoRoute.pageBuilder] for more info. + /// The codec used to encode and decode extra into a serializable format. + /// + /// When navigating using [GoRouter.go] or [GoRouter.push], one can provide + /// an `extra` parameter along with it. If the extra contains complex data, + /// consider provide a codec for serializing and deserializing the extra data. + /// + /// See also: + /// * [Navigation](https://pub.dev/documentation/go_router/latest/topics/Navigation-topic.html) + /// topic. + /// * [extra_codec](https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/extra_codec.dart) + /// example. final Codec? extraCodec; /// The GoRouter instance that owns this configuration. From c93570b61f1a88275279158fdf47b1c589c34885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Sasovsky?= Date: Wed, 30 Jul 2025 17:00:53 -0300 Subject: [PATCH 03/10] refactor: replace _currentRouterKey with currentRouterKey constant for redirect context tracking --- packages/go_router/lib/src/configuration.dart | 6 ++--- .../go_router/lib/src/misc/constants.dart | 5 +++++ packages/go_router/lib/src/router.dart | 22 +++++-------------- 3 files changed, 13 insertions(+), 20 deletions(-) create mode 100644 packages/go_router/lib/src/misc/constants.dart diff --git a/packages/go_router/lib/src/configuration.dart b/packages/go_router/lib/src/configuration.dart index 2293e88b37e..ba61d475fd6 100644 --- a/packages/go_router/lib/src/configuration.dart +++ b/packages/go_router/lib/src/configuration.dart @@ -10,15 +10,13 @@ import 'package:flutter/widgets.dart'; import 'logging.dart'; import 'match.dart'; +import 'misc/constants.dart'; import 'misc/errors.dart'; import 'path_utils.dart'; import 'route.dart'; import 'router.dart'; import 'state.dart'; -/// Symbol used as a Zone key to track the current GoRouter during redirects. -const Symbol _currentRouterKey = #goRouterRedirectContext; - /// The signature of the redirect callback. typedef GoRouterRedirect = FutureOr Function( BuildContext context, GoRouterState state); @@ -529,7 +527,7 @@ class RouteConfiguration { return runZoned( callback, zoneValues: { - _currentRouterKey: router, + currentRouterKey: router, }, ); } diff --git a/packages/go_router/lib/src/misc/constants.dart b/packages/go_router/lib/src/misc/constants.dart new file mode 100644 index 00000000000..2a89463c3c2 --- /dev/null +++ b/packages/go_router/lib/src/misc/constants.dart @@ -0,0 +1,5 @@ +import 'package:meta/meta.dart'; + +/// Symbol used as a Zone key to track the current GoRouter during redirects. +@internal +const Symbol currentRouterKey = #goRouterRedirectContext; diff --git a/packages/go_router/lib/src/router.dart b/packages/go_router/lib/src/router.dart index 31e8fa3ef4d..305a620899d 100644 --- a/packages/go_router/lib/src/router.dart +++ b/packages/go_router/lib/src/router.dart @@ -13,14 +13,12 @@ import 'delegate.dart'; import 'information_provider.dart'; import 'logging.dart'; import 'match.dart'; +import 'misc/constants.dart'; import 'misc/inherited_router.dart'; import 'parser.dart'; import 'route.dart'; import 'state.dart'; -/// Symbol used as a Zone key to track the current GoRouter during redirects. -const Symbol _currentRouterKey = #goRouterRedirectContext; - /// The function signature of [GoRouter.onException]. /// /// Use `state.error` to access the exception. @@ -525,19 +523,11 @@ class GoRouter implements RouterConfig { /// /// This method can now be called during redirects. static GoRouter of(BuildContext context) { - final GoRouter? inherited = maybeOf(context); - if (inherited != null) { - return inherited; - } - - // Check if we're in a redirect context - final GoRouter? redirectRouter = - Zone.current[_currentRouterKey] as GoRouter?; - if (redirectRouter != null) { - return redirectRouter; + final GoRouter? router = maybeOf(context); + if (router == null) { + throw FlutterError('No GoRouter found in context'); } - - throw FlutterError('No GoRouter found in context'); + return router; } /// The current GoRouter in the widget tree, if any. @@ -553,7 +543,7 @@ class GoRouter implements RouterConfig { } // Check if we're in a redirect context - return Zone.current[_currentRouterKey] as GoRouter?; + return Zone.current[currentRouterKey] as GoRouter?; } /// Disposes resource created by this object. From 858ea74467f70b9fb8509181e6ee6a002158f817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Sasovsky?= Date: Thu, 31 Jul 2025 13:25:06 -0300 Subject: [PATCH 04/10] chore: release version 16.0.1 with fixes for redirect callbacks and context extension methods --- packages/go_router/CHANGELOG.md | 5 +++++ packages/go_router/pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md index b4f32dc31ed..3641c1a489f 100644 --- a/packages/go_router/CHANGELOG.md +++ b/packages/go_router/CHANGELOG.md @@ -1,3 +1,8 @@ +## 16.0.1 + +- Fixes `GoRouter.of(context)` access inside redirect callbacks by providing router access through Zone-based context tracking. +- Adds support for using context extension methods (e.g., `context.namedLocation()`, `context.go()`) within redirect callbacks. + ## 16.0.0 - **BREAKING CHANGE** diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml index 3debeeaf158..6a3256aa7dd 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: 16.0.0 +version: 16.0.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 From 61bc8ffc3a9ab59b68ec78198e2175f652054dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Sasovsky?= Date: Thu, 31 Jul 2025 13:37:14 -0300 Subject: [PATCH 05/10] refactor: update documentation for GoRouter context methods to clarify usage during redirects --- packages/go_router/lib/src/router.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/go_router/lib/src/router.dart b/packages/go_router/lib/src/router.dart index 305a620899d..6f2d85d2977 100644 --- a/packages/go_router/lib/src/router.dart +++ b/packages/go_router/lib/src/router.dart @@ -520,8 +520,6 @@ class GoRouter implements RouterConfig { } /// Find the current GoRouter in the widget tree. - /// - /// This method can now be called during redirects. static GoRouter of(BuildContext context) { final GoRouter? router = maybeOf(context); if (router == null) { @@ -531,8 +529,6 @@ class GoRouter implements RouterConfig { } /// The current GoRouter in the widget tree, if any. - /// - /// This method can now return a router even during redirects. static GoRouter? maybeOf(BuildContext context) { final InheritedGoRouter? inherited = context .getElementForInheritedWidgetOfExactType() From 6309387aa5e54708e77f2cde636843acec479d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Sasovsky?= Date: Fri, 1 Aug 2025 17:21:11 -0300 Subject: [PATCH 06/10] feat: implement error handling in router zone for GoRouter --- packages/go_router/lib/src/configuration.dart | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/go_router/lib/src/configuration.dart b/packages/go_router/lib/src/configuration.dart index ba61d475fd6..e34958916e9 100644 --- a/packages/go_router/lib/src/configuration.dart +++ b/packages/go_router/lib/src/configuration.dart @@ -251,6 +251,7 @@ class RouteConfiguration { final Codec? extraCodec; /// The GoRouter instance that owns this configuration. + /// /// This is used to provide access to the router during redirects. final GoRouter? router; @@ -529,6 +530,28 @@ class RouteConfiguration { zoneValues: { currentRouterKey: router, }, + zoneSpecification: ZoneSpecification( + handleUncaughtError: ( + Zone zone, + ZoneDelegate zoneDelegate, + Zone zone2, + Object error, + StackTrace stackTrace, + ) { + // Handle errors by routing them to GoRouter's error handling mechanisms + if (error is GoException) { + // For GoException, we can let it propagate as it's already handled + // by the existing error handling in redirect methods + throw error; + } else { + // For other errors, we should route them to the router's error handling + // This will be handled by GoRouter.onException or error builders + log('Error in router zone: $error'); + // Convert the error to a GoException for proper error handling + throw GoException('error in router zone: $error'); + } + }, + ), ); } From fec0356dcd91fcef12b540cf40b1b04ee9a752f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Sasovsky?= Date: Fri, 1 Aug 2025 23:14:15 -0300 Subject: [PATCH 07/10] refactor: replace runZoned with runZonedGuarded for improved error handling in router zone --- packages/go_router/lib/src/configuration.dart | 40 ++++++++----------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/packages/go_router/lib/src/configuration.dart b/packages/go_router/lib/src/configuration.dart index e34958916e9..78d29ff76fd 100644 --- a/packages/go_router/lib/src/configuration.dart +++ b/packages/go_router/lib/src/configuration.dart @@ -525,34 +525,26 @@ class RouteConfiguration { return callback(); } - return runZoned( + return runZonedGuarded( callback, + (Object error, StackTrace stackTrace) { + // Handle errors by routing them to GoRouter's error handling mechanisms + if (error is GoException) { + // For GoException, we can let it propagate as it's already handled + // by the existing error handling in redirect methods + throw error; + } else { + // For other errors, we should route them to the router's error handling + // This will be handled by GoRouter.onException or error builders + log('Error in router zone: $error'); + // Convert the error to a GoException for proper error handling + throw GoException('error in router zone: $error'); + } + }, zoneValues: { currentRouterKey: router, }, - zoneSpecification: ZoneSpecification( - handleUncaughtError: ( - Zone zone, - ZoneDelegate zoneDelegate, - Zone zone2, - Object error, - StackTrace stackTrace, - ) { - // Handle errors by routing them to GoRouter's error handling mechanisms - if (error is GoException) { - // For GoException, we can let it propagate as it's already handled - // by the existing error handling in redirect methods - throw error; - } else { - // For other errors, we should route them to the router's error handling - // This will be handled by GoRouter.onException or error builders - log('Error in router zone: $error'); - // Convert the error to a GoException for proper error handling - throw GoException('error in router zone: $error'); - } - }, - ), - ); + )!; } /// Get the location for the provided route. From 2cdaa913e57faa6f928bf6730bef79297c478ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Sasovsky?= Date: Tue, 5 Aug 2025 00:39:13 -0300 Subject: [PATCH 08/10] feat: enhance error handling in redirect callbacks and tests for GoRouter --- packages/go_router/lib/src/configuration.dart | 111 ++++++++++++------ packages/go_router/lib/src/parser.dart | 39 +++++- .../test/exception_handling_test.dart | 93 +++++++++++++++ packages/go_router/test/go_router_test.dart | 44 +++++-- 4 files changed, 237 insertions(+), 50 deletions(-) diff --git a/packages/go_router/lib/src/configuration.dart b/packages/go_router/lib/src/configuration.dart index 78d29ff76fd..9426103859b 100644 --- a/packages/go_router/lib/src/configuration.dart +++ b/packages/go_router/lib/src/configuration.dart @@ -411,14 +411,30 @@ class RouteConfiguration { } return true; }); - final FutureOr routeLevelRedirectResult = - _getRouteLevelRedirect(context, prevMatchList, routeMatches, 0); - if (routeLevelRedirectResult is String?) { - return processRouteLevelRedirect(routeLevelRedirectResult); + try { + final FutureOr routeLevelRedirectResult = + _getRouteLevelRedirect(context, prevMatchList, routeMatches, 0); + + if (routeLevelRedirectResult is String?) { + return processRouteLevelRedirect(routeLevelRedirectResult); + } + return routeLevelRedirectResult + .then(processRouteLevelRedirect) + .catchError((Object error) { + final GoException goException = error is GoException + ? error + : GoException('Exception during route redirect: $error'); + return _errorRouteMatchList(prevMatchList.uri, goException, + extra: prevMatchList.extra); + }); + } catch (exception) { + final GoException goException = exception is GoException + ? exception + : GoException('Exception during route redirect: $exception'); + return _errorRouteMatchList(prevMatchList.uri, goException, + extra: prevMatchList.extra); } - return routeLevelRedirectResult - .then(processRouteLevelRedirect); } redirectHistory.add(prevMatchList); @@ -457,16 +473,34 @@ class RouteConfiguration { _getRouteLevelRedirect( context, matchList, routeMatches, currentCheckIndex + 1); final RouteBase route = match.route; - final FutureOr routeRedirectResult = _runInRouterZone(() { - return route.redirect!.call( - context, - match.buildState(this, matchList), - ); - }); - if (routeRedirectResult is String?) { - return processRouteRedirect(routeRedirectResult); + try { + final FutureOr routeRedirectResult = _runInRouterZone(() { + return route.redirect!.call( + context, + match.buildState(this, matchList), + ); + }); + if (routeRedirectResult is String?) { + return processRouteRedirect(routeRedirectResult); + } + return routeRedirectResult + .then(processRouteRedirect) + .catchError((Object error) { + // Convert any exception during async route redirect to a GoException + final GoException goException = error is GoException + ? error + : GoException('Exception during route redirect: $error'); + // Throw the GoException to be caught by the redirect handling chain + throw goException; + }); + } catch (exception) { + // Convert any exception during route redirect to a GoException + final GoException goException = exception is GoException + ? exception + : GoException('Exception during route redirect: $exception'); + // Throw the GoException to be caught by the redirect handling chain + throw goException; } - return routeRedirectResult.then(processRouteRedirect); } RouteMatchList _getNewMatches( @@ -478,9 +512,12 @@ class RouteConfiguration { final RouteMatchList newMatch = findMatch(Uri.parse(newLocation)); _addRedirect(redirectHistory, newMatch, previousLocation); return newMatch; - } on GoException catch (e) { - log('Redirection exception: ${e.message}'); - return _errorRouteMatchList(previousLocation, e); + } catch (exception) { + final GoException goException = exception is GoException + ? exception + : GoException('Exception during redirect: $exception'); + log('Redirection exception: ${goException.message}'); + return _errorRouteMatchList(previousLocation, goException); } } @@ -525,26 +562,32 @@ class RouteConfiguration { return callback(); } - return runZonedGuarded( - callback, - (Object error, StackTrace stackTrace) { - // Handle errors by routing them to GoRouter's error handling mechanisms - if (error is GoException) { - // For GoException, we can let it propagate as it's already handled - // by the existing error handling in redirect methods - throw error; - } else { - // For other errors, we should route them to the router's error handling - // This will be handled by GoRouter.onException or error builders - log('Error in router zone: $error'); - // Convert the error to a GoException for proper error handling - throw GoException('error in router zone: $error'); - } + T? result; + bool errorOccurred = false; + + runZonedGuarded( + () { + result = callback(); + }, + (Object error, StackTrace stack) { + errorOccurred = true; + // Convert any exception during redirect to a GoException and rethrow + final GoException goException = error is GoException + ? error + : GoException('Exception during redirect: $error'); + throw goException; }, zoneValues: { currentRouterKey: router, }, - )!; + ); + + if (errorOccurred) { + // This should not be reached since we rethrow in the error handler + throw GoException('Unexpected error in router zone'); + } + + return result as T; } /// Get the location for the provided route. diff --git a/packages/go_router/lib/src/parser.dart b/packages/go_router/lib/src/parser.dart index d1981898a8b..7d67351e8a2 100644 --- a/packages/go_router/lib/src/parser.dart +++ b/packages/go_router/lib/src/parser.dart @@ -12,6 +12,7 @@ import 'configuration.dart'; import 'information_provider.dart'; import 'logging.dart'; import 'match.dart'; +import 'misc/errors.dart'; import 'router.dart'; /// The function signature of [GoRouteInformationParser.onParserException]. @@ -160,12 +161,40 @@ class GoRouteInformationParser extends RouteInformationParser { Future _redirect( BuildContext context, RouteMatchList routeMatch) { - final FutureOr redirectedFuture = configuration - .redirect(context, routeMatch, redirectHistory: []); - if (redirectedFuture is RouteMatchList) { - return SynchronousFuture(redirectedFuture); + try { + final FutureOr redirectedFuture = configuration + .redirect(context, routeMatch, redirectHistory: []); + if (redirectedFuture is RouteMatchList) { + return SynchronousFuture(redirectedFuture); + } + return redirectedFuture.catchError((Object error) { + // Convert any exception during redirect to a GoException + final GoException goException = error is GoException + ? error + : GoException('Exception during redirect: $error'); + // Return an error match list instead of throwing + return RouteMatchList( + matches: const [], + extra: routeMatch.extra, + error: goException, + uri: routeMatch.uri, + pathParameters: const {}, + ); + }); + } catch (exception) { + // Convert any exception during redirect to a GoException + final GoException goException = exception is GoException + ? exception + : GoException('Exception during redirect: $exception'); + // Return an error match list instead of throwing + return SynchronousFuture(RouteMatchList( + matches: const [], + extra: routeMatch.extra, + error: goException, + uri: routeMatch.uri, + pathParameters: const {}, + )); } - return redirectedFuture; } RouteMatchList _updateRouteMatchList( diff --git a/packages/go_router/test/exception_handling_test.dart b/packages/go_router/test/exception_handling_test.dart index d8ad3c3f565..4fb140be985 100644 --- a/packages/go_router/test/exception_handling_test.dart +++ b/packages/go_router/test/exception_handling_test.dart @@ -108,5 +108,98 @@ void main() { await tester.pumpAndSettle(); expect(find.text('home'), findsOneWidget); }); + + testWidgets('can catch errors thrown in redirect callbacks', (WidgetTester tester) async { + bool exceptionCaught = false; + String? errorMessage; + + final GoRouter router = await createRouter( + [ + GoRoute( + path: '/', + builder: (_, GoRouterState state) => const Text('home'), + ), + GoRoute( + path: '/error-page', + builder: (_, GoRouterState state) => Text('error handled: ${state.extra}'), + ), + GoRoute( + path: '/trigger-error', + builder: (_, GoRouterState state) => const Text('should not reach here'), + ), + ], + tester, + redirect: (BuildContext context, GoRouterState state) { + if (state.matchedLocation == '/trigger-error') { + // Simulate an error in redirect callback + throw Exception('Redirect error occurred'); + } + return null; + }, + onException: (BuildContext context, GoRouterState state, GoRouter router) { + exceptionCaught = true; + errorMessage = 'Caught exception for ${state.uri}'; + router.go('/error-page', extra: errorMessage); + }, + ); + + expect(find.text('home'), findsOneWidget); + expect(exceptionCaught, isFalse); + + // Navigate to a route that will trigger an error in the redirect callback + router.go('/trigger-error'); + await tester.pumpAndSettle(); + + // Verify the exception was caught and handled + expect(exceptionCaught, isTrue); + expect(errorMessage, isNotNull); + expect(find.text('error handled: Caught exception for /trigger-error'), findsOneWidget); + expect(find.text('should not reach here'), findsNothing); + }); + + testWidgets('can catch non-GoException errors thrown in redirect callbacks', (WidgetTester tester) async { + bool exceptionCaught = false; + + final GoRouter router = await createRouter( + [ + GoRoute( + path: '/', + builder: (_, GoRouterState state) => const Text('home'), + ), + GoRoute( + path: '/error-page', + builder: (_, GoRouterState state) => const Text('generic error handled'), + ), + GoRoute( + path: '/trigger-runtime-error', + builder: (_, GoRouterState state) => const Text('should not reach here'), + ), + ], + tester, + redirect: (BuildContext context, GoRouterState state) { + if (state.matchedLocation == '/trigger-runtime-error') { + // Simulate a runtime error (not GoException) + throw StateError('Runtime error in redirect'); + } + return null; + }, + onException: (BuildContext context, GoRouterState state, GoRouter router) { + exceptionCaught = true; + router.go('/error-page'); + }, + ); + + expect(find.text('home'), findsOneWidget); + expect(exceptionCaught, isFalse); + + // Navigate to a route that will trigger a runtime error in the redirect callback + router.go('/trigger-runtime-error'); + await tester.pumpAndSettle(); + + // Verify the exception was caught and handled + expect(exceptionCaught, isTrue); + expect(find.text('generic error handled'), findsOneWidget); + expect(find.text('should not reach here'), findsNothing); + }); }); } diff --git a/packages/go_router/test/go_router_test.dart b/packages/go_router/test/go_router_test.dart index e8d27639d08..93a861a603f 100644 --- a/packages/go_router/test/go_router_test.dart +++ b/packages/go_router/test/go_router_test.dart @@ -2238,9 +2238,9 @@ void main() { expect(redirected, isTrue); }); - testWidgets('GoRouter.of(context) should work in redirects', + testWidgets('error thrown during redirect can be caught by onException', (WidgetTester tester) async { - GoRouter? capturedRouter; + bool exceptionCaught = false; final List routes = [ GoRoute( path: '/', @@ -2252,19 +2252,41 @@ void main() { builder: (BuildContext context, GoRouterState state) => const LoginScreen(), ), + GoRoute( + path: '/trigger-error', + builder: (BuildContext context, GoRouterState state) => + const Text('should not reach here'), + ), ]; - final GoRouter router = await createRouter(routes, tester, - redirect: (BuildContext context, GoRouterState state) { - // This should not throw an exception - capturedRouter = GoRouter.of(context); - return state.matchedLocation == '/login' ? null : '/login'; - }); + final GoRouter router = await createRouter( + routes, + tester, + redirect: (BuildContext context, GoRouterState state) { + if (state.matchedLocation == '/trigger-error') { + throw Exception('Redirect error'); + } + return null; + }, + onException: + (BuildContext context, GoRouterState state, GoRouter router) { + exceptionCaught = true; + }, + ); - expect(capturedRouter, isNotNull); - expect(capturedRouter, equals(router)); - }); + expect(find.byType(HomeScreen), findsOneWidget); + expect(exceptionCaught, isFalse); + + // Navigate to a route that will trigger an error in the redirect callback + router.go('/trigger-error'); + await tester.pumpAndSettle(); + // Verify the exception was caught + expect(exceptionCaught, isTrue); + // Should stay on the home screen since onException didn't navigate anywhere + expect(find.byType(HomeScreen), findsOneWidget); + expect(find.text('should not reach here'), findsNothing); + }); testWidgets('Context extension methods should work in redirects', (WidgetTester tester) async { String? capturedNamedLocation; From 05c1cbcef287181c908cb454ee7b9321fbabbf2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Sasovsky?= Date: Wed, 24 Sep 2025 23:47:24 -0300 Subject: [PATCH 09/10] chore: dart format --- packages/go_router/lib/src/configuration.dart | 97 +- packages/go_router/lib/src/parser.dart | 39 +- packages/go_router/lib/src/router.dart | 105 +- .../test/exception_handling_test.dart | 50 +- packages/go_router/test/go_router_test.dart | 1250 ++++++++++------- 5 files changed, 867 insertions(+), 674 deletions(-) diff --git a/packages/go_router/lib/src/configuration.dart b/packages/go_router/lib/src/configuration.dart index 89bd7775842..683c88f8ed7 100644 --- a/packages/go_router/lib/src/configuration.dart +++ b/packages/go_router/lib/src/configuration.dart @@ -18,8 +18,8 @@ import 'router.dart'; import 'state.dart'; /// The signature of the redirect callback. -typedef GoRouterRedirect = FutureOr Function( - BuildContext context, GoRouterState state); +typedef GoRouterRedirect = + FutureOr Function(BuildContext context, GoRouterState state); typedef _NamedPath = ({String path, bool caseSensitive}); @@ -448,18 +448,28 @@ class RouteConfiguration { return routeLevelRedirectResult .then(processRouteLevelRedirect) .catchError((Object error) { - final GoException goException = error is GoException - ? error - : GoException('Exception during route redirect: $error'); - return _errorRouteMatchList(prevMatchList.uri, goException, - extra: prevMatchList.extra); - }); + final GoException goException = + error is GoException + ? error + : GoException( + 'Exception during route redirect: $error', + ); + return _errorRouteMatchList( + prevMatchList.uri, + goException, + extra: prevMatchList.extra, + ); + }); } catch (exception) { - final GoException goException = exception is GoException - ? exception - : GoException('Exception during route redirect: $exception'); - return _errorRouteMatchList(prevMatchList.uri, goException, - extra: prevMatchList.extra); + final GoException goException = + exception is GoException + ? exception + : GoException('Exception during route redirect: $exception'); + return _errorRouteMatchList( + prevMatchList.uri, + goException, + extra: prevMatchList.extra, + ); } } @@ -505,29 +515,28 @@ class RouteConfiguration { final RouteBase route = match.route; try { final FutureOr routeRedirectResult = _runInRouterZone(() { - return route.redirect!.call( - context, - match.buildState(this, matchList), - ); + return route.redirect!.call(context, match.buildState(this, matchList)); }); if (routeRedirectResult is String?) { return processRouteRedirect(routeRedirectResult); } - return routeRedirectResult - .then(processRouteRedirect) - .catchError((Object error) { - // Convert any exception during async route redirect to a GoException - final GoException goException = error is GoException - ? error - : GoException('Exception during route redirect: $error'); - // Throw the GoException to be caught by the redirect handling chain - throw goException; - }); + return routeRedirectResult.then(processRouteRedirect).catchError( + (Object error) { + // Convert any exception during async route redirect to a GoException + final GoException goException = + error is GoException + ? error + : GoException('Exception during route redirect: $error'); + // Throw the GoException to be caught by the redirect handling chain + throw goException; + }, + ); } catch (exception) { // Convert any exception during route redirect to a GoException - final GoException goException = exception is GoException - ? exception - : GoException('Exception during route redirect: $exception'); + final GoException goException = + exception is GoException + ? exception + : GoException('Exception during route redirect: $exception'); // Throw the GoException to be caught by the redirect handling chain throw goException; } @@ -543,9 +552,10 @@ class RouteConfiguration { _addRedirect(redirectHistory, newMatch, previousLocation); return newMatch; } catch (exception) { - final GoException goException = exception is GoException - ? exception - : GoException('Exception during redirect: $exception'); + final GoException goException = + exception is GoException + ? exception + : GoException('Exception during redirect: $exception'); log('Redirection exception: ${goException.message}'); return _errorRouteMatchList(previousLocation, goException); } @@ -561,18 +571,12 @@ class RouteConfiguration { ) { if (redirects.contains(newMatch)) { throw GoException( - 'redirect loop detected ${_formatRedirectionHistory([ - ...redirects, - newMatch - ])}', + 'redirect loop detected ${_formatRedirectionHistory([...redirects, newMatch])}', ); } if (redirects.length > _routingConfig.value.redirectLimit) { throw GoException( - 'too many redirects ${_formatRedirectionHistory([ - ...redirects, - newMatch - ])}', + 'too many redirects ${_formatRedirectionHistory([...redirects, newMatch])}', ); } @@ -605,14 +609,13 @@ class RouteConfiguration { (Object error, StackTrace stack) { errorOccurred = true; // Convert any exception during redirect to a GoException and rethrow - final GoException goException = error is GoException - ? error - : GoException('Exception during redirect: $error'); + final GoException goException = + error is GoException + ? error + : GoException('Exception during redirect: $error'); throw goException; }, - zoneValues: { - currentRouterKey: router, - }, + zoneValues: {currentRouterKey: router}, ); if (errorOccurred) { diff --git a/packages/go_router/lib/src/parser.dart b/packages/go_router/lib/src/parser.dart index f0a9236d4bc..020a5bbb657 100644 --- a/packages/go_router/lib/src/parser.dart +++ b/packages/go_router/lib/src/parser.dart @@ -22,10 +22,11 @@ import 'router.dart'; /// /// The returned [RouteMatchList] is used as parsed result for the /// [GoRouterDelegate]. -typedef ParserExceptionHandler = RouteMatchList Function( - BuildContext context, - RouteMatchList routeMatchList, -); +typedef ParserExceptionHandler = + RouteMatchList Function( + BuildContext context, + RouteMatchList routeMatchList, + ); /// Converts between incoming URLs and a [RouteMatchList] using [RouteMatcher]. /// Also performs redirection using [RouteRedirector]. @@ -181,9 +182,10 @@ class GoRouteInformationParser extends RouteInformationParser { } return redirectedFuture.catchError((Object error) { // Convert any exception during redirect to a GoException - final GoException goException = error is GoException - ? error - : GoException('Exception during redirect: $error'); + final GoException goException = + error is GoException + ? error + : GoException('Exception during redirect: $error'); // Return an error match list instead of throwing return RouteMatchList( matches: const [], @@ -195,17 +197,20 @@ class GoRouteInformationParser extends RouteInformationParser { }); } catch (exception) { // Convert any exception during redirect to a GoException - final GoException goException = exception is GoException - ? exception - : GoException('Exception during redirect: $exception'); + final GoException goException = + exception is GoException + ? exception + : GoException('Exception during redirect: $exception'); // Return an error match list instead of throwing - return SynchronousFuture(RouteMatchList( - matches: const [], - extra: routeMatch.extra, - error: goException, - uri: routeMatch.uri, - pathParameters: const {}, - )); + return SynchronousFuture( + RouteMatchList( + matches: const [], + extra: routeMatch.extra, + error: goException, + uri: routeMatch.uri, + pathParameters: const {}, + ), + ); } } diff --git a/packages/go_router/lib/src/router.dart b/packages/go_router/lib/src/router.dart index 4e8e2f619df..cd76b594c39 100644 --- a/packages/go_router/lib/src/router.dart +++ b/packages/go_router/lib/src/router.dart @@ -22,8 +22,8 @@ import 'state.dart'; /// The function signature of [GoRouter.onException]. /// /// Use `state.error` to access the exception. -typedef GoExceptionHandler = void Function( - BuildContext context, GoRouterState state, GoRouter router); +typedef GoExceptionHandler = + void Function(BuildContext context, GoRouterState state, GoRouter router); /// A set of parameters that defines routing in GoRouter. /// @@ -46,8 +46,7 @@ class RoutingConfig { static FutureOr _defaultRedirect( BuildContext context, GoRouterState state, - ) => - null; + ) => null; /// The supported routes. /// @@ -184,23 +183,23 @@ class GoRouter implements RouterConfig { GlobalKey? navigatorKey, String? restorationScopeId, bool requestFocus = true, - }) : _routingConfig = routingConfig, - backButtonDispatcher = RootBackButtonDispatcher(), - assert( - initialExtra == null || initialLocation != null, - 'initialLocation must be set in order to use initialExtra', - ), - assert( - !overridePlatformDefaultLocation || initialLocation != null, - 'Initial location must be set to override platform default', - ), - assert( - (onException == null ? 0 : 1) + - (errorPageBuilder == null ? 0 : 1) + - (errorBuilder == null ? 0 : 1) < - 2, - 'Only one of onException, errorPageBuilder, or errorBuilder can be provided.', - ) { + }) : _routingConfig = routingConfig, + backButtonDispatcher = RootBackButtonDispatcher(), + assert( + initialExtra == null || initialLocation != null, + 'initialLocation must be set in order to use initialExtra', + ), + assert( + !overridePlatformDefaultLocation || initialLocation != null, + 'Initial location must be set to override platform default', + ), + assert( + (onException == null ? 0 : 1) + + (errorPageBuilder == null ? 0 : 1) + + (errorBuilder == null ? 0 : 1) < + 2, + 'Only one of onException, errorPageBuilder, or errorBuilder can be provided.', + ) { setLogging(enabled: debugLogDiagnostics); WidgetsFlutterBinding.ensureInitialized(); @@ -254,8 +253,9 @@ class GoRouter implements RouterConfig { requestFocus: requestFocus, // wrap the returned Navigator to enable GoRouter.of(context).go() et al, // allowing the caller to wrap the navigator themselves - builderWithNav: (BuildContext context, Widget child) => - InheritedGoRouter(goRouter: this, child: child), + builderWithNav: + (BuildContext context, Widget child) => + InheritedGoRouter(goRouter: this, child: child), ); assert(() { @@ -345,13 +345,12 @@ class GoRouter implements RouterConfig { Map pathParameters = const {}, Map queryParameters = const {}, String? fragment, - }) => - configuration.namedLocation( - name, - pathParameters: pathParameters, - queryParameters: queryParameters, - fragment: fragment, - ); + }) => configuration.namedLocation( + name, + pathParameters: pathParameters, + queryParameters: queryParameters, + fragment: fragment, + ); /// Navigate to a URI location w/ optional query parameters, e.g. /// `/family/f2/person/p1?color=blue` @@ -379,17 +378,16 @@ class GoRouter implements RouterConfig { Object? extra, String? fragment, }) => - - /// Construct location with optional fragment, using null-safe navigation - go( - namedLocation( - name, - pathParameters: pathParameters, - queryParameters: queryParameters, - fragment: fragment, - ), - extra: extra, - ); + /// Construct location with optional fragment, using null-safe navigation + go( + namedLocation( + name, + pathParameters: pathParameters, + queryParameters: queryParameters, + fragment: fragment, + ), + extra: extra, + ); /// Push a URI location onto the page stack w/ optional query parameters, e.g. /// `/family/f2/person/p1?color=blue`. @@ -416,15 +414,14 @@ class GoRouter implements RouterConfig { Map pathParameters = const {}, Map queryParameters = const {}, Object? extra, - }) => - push( - namedLocation( - name, - pathParameters: pathParameters, - queryParameters: queryParameters, - ), - extra: extra, - ); + }) => push( + namedLocation( + name, + pathParameters: pathParameters, + queryParameters: queryParameters, + ), + extra: extra, + ); /// Replaces the top-most page of the page stack with the given URL location /// w/ optional query parameters, e.g. `/family/f2/person/p1?color=blue`. @@ -552,9 +549,11 @@ class GoRouter implements RouterConfig { /// The current GoRouter in the widget tree, if any. static GoRouter? maybeOf(BuildContext context) { - final InheritedGoRouter? inherited = context - .getElementForInheritedWidgetOfExactType() - ?.widget as InheritedGoRouter?; + final InheritedGoRouter? inherited = + context + .getElementForInheritedWidgetOfExactType() + ?.widget + as InheritedGoRouter?; if (inherited != null) { return inherited.goRouter; } diff --git a/packages/go_router/test/exception_handling_test.dart b/packages/go_router/test/exception_handling_test.dart index 13b18352747..2aca1f9f3ca 100644 --- a/packages/go_router/test/exception_handling_test.dart +++ b/packages/go_router/test/exception_handling_test.dart @@ -124,10 +124,12 @@ void main() { expect(find.text('home'), findsOneWidget); }); - testWidgets('can catch errors thrown in redirect callbacks', (WidgetTester tester) async { + testWidgets('can catch errors thrown in redirect callbacks', ( + WidgetTester tester, + ) async { bool exceptionCaught = false; String? errorMessage; - + final GoRouter router = await createRouter( [ GoRoute( @@ -136,11 +138,14 @@ void main() { ), GoRoute( path: '/error-page', - builder: (_, GoRouterState state) => Text('error handled: ${state.extra}'), + builder: + (_, GoRouterState state) => + Text('error handled: ${state.extra}'), ), GoRoute( path: '/trigger-error', - builder: (_, GoRouterState state) => const Text('should not reach here'), + builder: + (_, GoRouterState state) => const Text('should not reach here'), ), ], tester, @@ -151,30 +156,39 @@ void main() { } return null; }, - onException: (BuildContext context, GoRouterState state, GoRouter router) { + onException: ( + BuildContext context, + GoRouterState state, + GoRouter router, + ) { exceptionCaught = true; errorMessage = 'Caught exception for ${state.uri}'; router.go('/error-page', extra: errorMessage); }, ); - + expect(find.text('home'), findsOneWidget); expect(exceptionCaught, isFalse); // Navigate to a route that will trigger an error in the redirect callback router.go('/trigger-error'); await tester.pumpAndSettle(); - + // Verify the exception was caught and handled expect(exceptionCaught, isTrue); expect(errorMessage, isNotNull); - expect(find.text('error handled: Caught exception for /trigger-error'), findsOneWidget); + expect( + find.text('error handled: Caught exception for /trigger-error'), + findsOneWidget, + ); expect(find.text('should not reach here'), findsNothing); }); - testWidgets('can catch non-GoException errors thrown in redirect callbacks', (WidgetTester tester) async { + testWidgets('can catch non-GoException errors thrown in redirect callbacks', ( + WidgetTester tester, + ) async { bool exceptionCaught = false; - + final GoRouter router = await createRouter( [ GoRoute( @@ -183,11 +197,13 @@ void main() { ), GoRoute( path: '/error-page', - builder: (_, GoRouterState state) => const Text('generic error handled'), + builder: + (_, GoRouterState state) => const Text('generic error handled'), ), GoRoute( path: '/trigger-runtime-error', - builder: (_, GoRouterState state) => const Text('should not reach here'), + builder: + (_, GoRouterState state) => const Text('should not reach here'), ), ], tester, @@ -198,19 +214,23 @@ void main() { } return null; }, - onException: (BuildContext context, GoRouterState state, GoRouter router) { + onException: ( + BuildContext context, + GoRouterState state, + GoRouter router, + ) { exceptionCaught = true; router.go('/error-page'); }, ); - + expect(find.text('home'), findsOneWidget); expect(exceptionCaught, isFalse); // Navigate to a route that will trigger a runtime error in the redirect callback router.go('/trigger-runtime-error'); await tester.pumpAndSettle(); - + // Verify the exception was caught and handled expect(exceptionCaught, isTrue); expect(find.text('generic error handled'), findsOneWidget); diff --git a/packages/go_router/test/go_router_test.dart b/packages/go_router/test/go_router_test.dart index 369fd1b02b1..0b4dc08e6fa 100644 --- a/packages/go_router/test/go_router_test.dart +++ b/packages/go_router/test/go_router_test.dart @@ -45,8 +45,8 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), ]; @@ -126,8 +126,9 @@ void main() { final GoRouter router = await createRouter( routes, tester, - errorBuilder: (BuildContext context, GoRouterState state) => - TestErrorScreen(state.error!), + errorBuilder: + (BuildContext context, GoRouterState state) => + TestErrorScreen(state.error!), ); router.go('/foo'); await tester.pumpAndSettle(); @@ -141,13 +142,14 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ]; @@ -167,20 +169,22 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'page1', - builder: (BuildContext context, GoRouterState state) => - const Page1Screen(), + builder: + (BuildContext context, GoRouterState state) => + const Page1Screen(), ), ], ), GoRoute( path: '/login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ]; @@ -200,13 +204,14 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ]; @@ -270,8 +275,9 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => + const HomeScreen(), ), ]; @@ -292,13 +298,15 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => + const HomeScreen(), ), GoRoute( path: '/login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ]; @@ -482,18 +490,18 @@ void main() { final List routes = [ GoRoute( path: '/', - pageBuilder: (_, __) => - const MaterialPage(child: HomeScreen()), + pageBuilder: + (_, __) => const MaterialPage(child: HomeScreen()), ), GoRoute( path: '/page1', - pageBuilder: (_, __) => - const MaterialPage(child: Page1Screen()), + pageBuilder: + (_, __) => const MaterialPage(child: Page1Screen()), ), GoRoute( path: '/page2', - pageBuilder: (_, __) => - const MaterialPage(child: Page2Screen()), + pageBuilder: + (_, __) => const MaterialPage(child: Page2Screen()), ), ]; final GoRouter router = await createRouter( @@ -528,13 +536,14 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ], ), @@ -556,25 +565,28 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'family/:fid', - builder: (BuildContext context, GoRouterState state) => - const FamilyScreen('dummy'), + builder: + (BuildContext context, GoRouterState state) => + const FamilyScreen('dummy'), routes: [ GoRoute( path: 'person/:pid', - builder: (BuildContext context, GoRouterState state) => - const PersonScreen('dummy', 'dummy'), + builder: + (BuildContext context, GoRouterState state) => + const PersonScreen('dummy', 'dummy'), ), ], ), GoRoute( path: 'login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ], ), @@ -634,28 +646,32 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'foo/bar', - builder: (BuildContext context, GoRouterState state) => - const FamilyScreen(''), + builder: + (BuildContext context, GoRouterState state) => + const FamilyScreen(''), ), GoRoute( path: 'bar', - builder: (BuildContext context, GoRouterState state) => - const Page1Screen(), + builder: + (BuildContext context, GoRouterState state) => + const Page1Screen(), ), GoRoute( path: 'foo', - builder: (BuildContext context, GoRouterState state) => - const Page2Screen(), + builder: + (BuildContext context, GoRouterState state) => + const Page2Screen(), routes: [ GoRoute( path: 'bar', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ], ), @@ -778,14 +794,15 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/family/:fid', caseSensitive: false, - builder: (BuildContext context, GoRouterState state) => - FamilyScreen(state.pathParameters['fid']!), + builder: + (BuildContext context, GoRouterState state) => + FamilyScreen(state.pathParameters['fid']!), ), ]; @@ -812,13 +829,14 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/family/:fid', - builder: (BuildContext context, GoRouterState state) => - FamilyScreen(state.pathParameters['fid']!), + builder: + (BuildContext context, GoRouterState state) => + FamilyScreen(state.pathParameters['fid']!), ), ]; @@ -849,18 +867,20 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/abc', - builder: (BuildContext context, GoRouterState state) => - const SizedBox(key: Key('abc')), + builder: + (BuildContext context, GoRouterState state) => + const SizedBox(key: Key('abc')), ), GoRoute( path: '/ABC', - builder: (BuildContext context, GoRouterState state) => - const SizedBox(key: Key('ABC')), + builder: + (BuildContext context, GoRouterState state) => + const SizedBox(key: Key('ABC')), ), ]; @@ -1013,11 +1033,11 @@ void main() { final List log = []; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, ( - MethodCall methodCall, - ) async { - log.add(methodCall); - return null; - }); + MethodCall methodCall, + ) async { + log.add(methodCall); + return null; + }); Future verify( AsyncCallback test, @@ -1063,11 +1083,11 @@ void main() { final List log = []; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, ( - MethodCall methodCall, - ) async { - log.add(methodCall); - return null; - }); + MethodCall methodCall, + ) async { + log.add(methodCall); + return null; + }); Future verify(AsyncCallback test, List expectations) async { log.clear(); @@ -1130,10 +1150,11 @@ void main() { GoRoute( path: '/', pageBuilder: (BuildContext context, GoRouterState state) { - final String value = context - .dependOnInheritedWidgetOfExactType()! - .notifier! - .value; + final String value = + context + .dependOnInheritedWidgetOfExactType()! + .notifier! + .value; return MaterialPage(key: state.pageKey, child: Text(value)); }, ), @@ -1161,11 +1182,11 @@ void main() { final List log = []; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, ( - MethodCall methodCall, - ) async { - log.add(methodCall); - return null; - }); + MethodCall methodCall, + ) async { + log.add(methodCall); + return null; + }); Future verify(AsyncCallback test, List expectations) async { log.clear(); @@ -1256,11 +1277,11 @@ void main() { GoRouter.optionURLReflectsImperativeAPIs = false; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.navigation, ( - MethodCall methodCall, - ) async { - log.add(methodCall); - return null; - }); + MethodCall methodCall, + ) async { + log.add(methodCall); + return null; + }); }); tearDown(() { GoRouter.optionURLReflectsImperativeAPIs = false; @@ -1276,8 +1297,9 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), routes: [ ShellRoute( builder: @@ -1286,8 +1308,9 @@ void main() { routes: [ GoRoute( path: 'c', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), ], ), @@ -1596,9 +1619,10 @@ void main() { routes: [ GoRoute( path: 'settings', - builder: (_, GoRouterState state) => DummyScreen( - key: ValueKey('settings-${state.extra}'), - ), + builder: + (_, GoRouterState state) => DummyScreen( + key: ValueKey('settings-${state.extra}'), + ), ), ], ), @@ -1692,8 +1716,8 @@ void main() { GoRoute( name: 'home', path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), ]; @@ -1733,14 +1757,15 @@ void main() { GoRoute( name: 'home', path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( name: 'login', path: '/login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ]; @@ -1753,14 +1778,15 @@ void main() { GoRoute( name: 'home', path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( name: 'login', path: 'login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ], ), @@ -1775,14 +1801,15 @@ void main() { GoRoute( name: 'home', path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( name: 'family', path: 'family/:fid', - builder: (BuildContext context, GoRouterState state) => - const FamilyScreen('dummy'), + builder: + (BuildContext context, GoRouterState state) => + const FamilyScreen('dummy'), routes: [ GoRoute( name: 'person', @@ -1813,20 +1840,22 @@ void main() { GoRoute( name: 'home', path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( name: 'family', path: 'family/:fid', - builder: (BuildContext context, GoRouterState state) => - const FamilyScreen('dummy'), + builder: + (BuildContext context, GoRouterState state) => + const FamilyScreen('dummy'), routes: [ GoRoute( name: 'person', path: 'person/:pid', - builder: (BuildContext context, GoRouterState state) => - const PersonScreen('dummy', 'dummy'), + builder: + (BuildContext context, GoRouterState state) => + const PersonScreen('dummy', 'dummy'), ), ], ), @@ -1845,14 +1874,15 @@ void main() { GoRoute( name: 'home', path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( name: 'family', path: 'family/:fid', - builder: (BuildContext context, GoRouterState state) => - const FamilyScreen('dummy'), + builder: + (BuildContext context, GoRouterState state) => + const FamilyScreen('dummy'), routes: [ GoRoute( name: 'PeRsOn', @@ -1885,8 +1915,9 @@ void main() { GoRoute( name: 'family', path: '/family/:fid', - builder: (BuildContext context, GoRouterState state) => - const FamilyScreen('dummy'), + builder: + (BuildContext context, GoRouterState state) => + const FamilyScreen('dummy'), ), ]; await expectLater(() async { @@ -1900,8 +1931,9 @@ void main() { GoRoute( name: 'family', path: '/family/:fid', - builder: (BuildContext context, GoRouterState state) => - const FamilyScreen('dummy'), + builder: + (BuildContext context, GoRouterState state) => + const FamilyScreen('dummy'), ), ]; await expectLater(() async { @@ -1918,17 +1950,18 @@ void main() { GoRoute(path: '/', builder: dummy, redirect: (_, __) => '/family/f2'), GoRoute( path: '/family/:fid', - builder: (BuildContext context, GoRouterState state) => - FamilyScreen(state.pathParameters['fid']!), + builder: + (BuildContext context, GoRouterState state) => + FamilyScreen(state.pathParameters['fid']!), routes: [ GoRoute( name: 'person', path: 'person:pid', - builder: (BuildContext context, GoRouterState state) => - PersonScreen( - state.pathParameters['fid']!, - state.pathParameters['pid']!, - ), + builder: + (BuildContext context, GoRouterState state) => PersonScreen( + state.pathParameters['fid']!, + state.pathParameters['pid']!, + ), ), ], ), @@ -2004,13 +2037,14 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ], ), @@ -2026,13 +2060,14 @@ void main() { final List routes = [ GoRoute( path: '/home', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ], ), @@ -2052,13 +2087,14 @@ void main() { final List routes = [ GoRoute( path: '/home', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'family/:fid', - builder: (BuildContext context, GoRouterState state) => - const FamilyScreen('dummy'), + builder: + (BuildContext context, GoRouterState state) => + const FamilyScreen('dummy'), routes: [ GoRoute( name: 'person', @@ -2099,13 +2135,14 @@ void main() { final List routes = [ GoRoute( path: '/home', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'family', - builder: (BuildContext context, GoRouterState state) => - const FamilyScreen('dummy'), + builder: + (BuildContext context, GoRouterState state) => + const FamilyScreen('dummy'), routes: [ GoRoute( path: 'person', @@ -2143,18 +2180,20 @@ void main() { final List routes = [ GoRoute( path: '/home', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'family/:fid', - builder: (BuildContext context, GoRouterState state) => - const FamilyScreen('dummy'), + builder: + (BuildContext context, GoRouterState state) => + const FamilyScreen('dummy'), routes: [ GoRoute( path: 'person/:pid', - builder: (BuildContext context, GoRouterState state) => - const PersonScreen('dummy', 'dummy'), + builder: + (BuildContext context, GoRouterState state) => + const PersonScreen('dummy', 'dummy'), ), ], ), @@ -2166,8 +2205,9 @@ void main() { routes, tester, initialLocation: '/home', - errorBuilder: (BuildContext context, GoRouterState state) => - TestErrorScreen(state.error!), + errorBuilder: + (BuildContext context, GoRouterState state) => + TestErrorScreen(state.error!), ); router.go('./family/person/$pid'); await tester.pumpAndSettle(); @@ -2182,18 +2222,20 @@ void main() { final List routes = [ GoRoute( path: '/home', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'family', - builder: (BuildContext context, GoRouterState state) => - const FamilyScreen('dummy'), + builder: + (BuildContext context, GoRouterState state) => + const FamilyScreen('dummy'), routes: [ GoRoute( path: 'person', - builder: (BuildContext context, GoRouterState state) => - const PersonScreen('dummy', 'dummy'), + builder: + (BuildContext context, GoRouterState state) => + const PersonScreen('dummy', 'dummy'), ), ], ), @@ -2205,8 +2247,9 @@ void main() { routes, tester, initialLocation: '/home', - errorBuilder: (BuildContext context, GoRouterState state) => - TestErrorScreen(state.error!), + errorBuilder: + (BuildContext context, GoRouterState state) => + TestErrorScreen(state.error!), ); router.go('person'); @@ -2279,10 +2322,11 @@ void main() { initialLocation: '/home', ); - final String loc = Uri( - path: 'page1', - queryParameters: {'param1': param1}, - ).toString(); + final String loc = + Uri( + path: 'page1', + queryParameters: {'param1': param1}, + ).toString(); router.go('./$loc'); await tester.pumpAndSettle(); @@ -2298,18 +2342,20 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'dummy', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), GoRoute( path: 'login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ], ), @@ -2343,24 +2389,27 @@ void main() { expect(redirected, isTrue); }); - testWidgets('error thrown during redirect can be caught by onException', - (WidgetTester tester) async { + testWidgets('error thrown during redirect can be caught by onException', ( + WidgetTester tester, + ) async { bool exceptionCaught = false; final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), GoRoute( path: '/trigger-error', - builder: (BuildContext context, GoRouterState state) => - const Text('should not reach here'), + builder: + (BuildContext context, GoRouterState state) => + const Text('should not reach here'), ), ]; @@ -2373,8 +2422,11 @@ void main() { } return null; }, - onException: - (BuildContext context, GoRouterState state, GoRouter router) { + onException: ( + BuildContext context, + GoRouterState state, + GoRouter router, + ) { exceptionCaught = true; }, ); @@ -2393,21 +2445,23 @@ void main() { expect(find.text('should not reach here'), findsNothing); }); - testWidgets('context extension methods work in redirects', - (WidgetTester tester) async { + testWidgets('context extension methods work in redirects', ( + WidgetTester tester, + ) async { String? capturedNamedLocation; final List routes = [ GoRoute( path: '/', name: 'home', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/login', name: 'login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ]; @@ -2429,15 +2483,16 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'dummy', // Return same location. redirect: (_, GoRouterState state) => state.uri.toString(), - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), ], ), @@ -2469,20 +2524,22 @@ void main() { GoRoute( name: 'home', path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( name: 'dummy', path: 'dummy', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), GoRoute( name: 'login', path: 'login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ], ), @@ -2491,10 +2548,11 @@ void main() { final GoRouter router = await createRouter( routes, tester, - redirect: (BuildContext context, GoRouterState state) => - state.matchedLocation == '/login' - ? null - : state.namedLocation('login'), + redirect: + (BuildContext context, GoRouterState state) => + state.matchedLocation == '/login' + ? null + : state.namedLocation('login'), ); expect( router.routerDelegate.currentConfiguration.uri.toString(), @@ -2506,19 +2564,21 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'dummy', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), redirect: (BuildContext context, GoRouterState state) => '/login', ), GoRoute( path: 'login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ], ), @@ -2539,13 +2599,14 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'dummy', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), redirect: (BuildContext context, GoRouterState state) { // should never be reached. assert(false); @@ -2554,13 +2615,15 @@ void main() { ), GoRoute( path: 'dummy2', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), GoRoute( path: 'login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ], ), @@ -2593,22 +2656,25 @@ void main() { GoRoute( name: 'home', path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( name: 'dummy', path: 'dummy', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), - redirect: (BuildContext context, GoRouterState state) => - state.namedLocation('login'), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), + redirect: + (BuildContext context, GoRouterState state) => + state.namedLocation('login'), ), GoRoute( name: 'login', path: 'login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ], ), @@ -2627,18 +2693,20 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'dummy1', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), GoRoute( path: 'dummy2', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), redirect: (BuildContext context, GoRouterState state) => '/', ), ], @@ -2648,8 +2716,9 @@ void main() { final GoRouter router = await createRouter( routes, tester, - redirect: (BuildContext context, GoRouterState state) => - state.matchedLocation == '/dummy1' ? '/dummy2' : null, + redirect: + (BuildContext context, GoRouterState state) => + state.matchedLocation == '/dummy1' ? '/dummy2' : null, ); router.go('/dummy1'); await tester.pump(); @@ -2660,14 +2729,16 @@ void main() { final GoRouter router = await createRouter( [], tester, - redirect: (BuildContext context, GoRouterState state) => - state.matchedLocation == '/' - ? '/login' - : state.matchedLocation == '/login' + redirect: + (BuildContext context, GoRouterState state) => + state.matchedLocation == '/' + ? '/login' + : state.matchedLocation == '/login' ? '/' : null, - errorBuilder: (BuildContext context, GoRouterState state) => - TestErrorScreen(state.error!), + errorBuilder: + (BuildContext context, GoRouterState state) => + TestErrorScreen(state.error!), ); final List matches = router.routerDelegate.currentConfiguration.matches; @@ -2694,8 +2765,9 @@ void main() { ), ], tester, - errorBuilder: (BuildContext context, GoRouterState state) => - TestErrorScreen(state.error!), + errorBuilder: + (BuildContext context, GoRouterState state) => + TestErrorScreen(state.error!), ); final List matches = @@ -2718,10 +2790,12 @@ void main() { ), ], tester, - redirect: (BuildContext context, GoRouterState state) => - state.matchedLocation == '/' ? '/login' : null, - errorBuilder: (BuildContext context, GoRouterState state) => - TestErrorScreen(state.error!), + redirect: + (BuildContext context, GoRouterState state) => + state.matchedLocation == '/' ? '/login' : null, + errorBuilder: + (BuildContext context, GoRouterState state) => + TestErrorScreen(state.error!), ); final List matches = @@ -2740,14 +2814,16 @@ void main() { final GoRouter router = await createRouter( [], tester, - redirect: (BuildContext context, GoRouterState state) => - state.matchedLocation == '/' - ? '/login?from=${state.uri}' - : state.matchedLocation == '/login' + redirect: + (BuildContext context, GoRouterState state) => + state.matchedLocation == '/' + ? '/login?from=${state.uri}' + : state.matchedLocation == '/login' ? '/' : null, - errorBuilder: (BuildContext context, GoRouterState state) => - TestErrorScreen(state.error!), + errorBuilder: + (BuildContext context, GoRouterState state) => + TestErrorScreen(state.error!), ); final List matches = @@ -2766,8 +2842,8 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/dummy', @@ -2788,13 +2864,14 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/login', - builder: (BuildContext context, GoRouterState state) => - const LoginScreen(), + builder: + (BuildContext context, GoRouterState state) => + const LoginScreen(), ), ]; @@ -2826,13 +2903,15 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), routes: [ GoRoute( path: ':id', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), ], ), @@ -2896,8 +2975,9 @@ void main() { routes: [ GoRoute( path: 'family/:fid', - builder: (BuildContext c, GoRouterState s) => - FamilyScreen(s.pathParameters['fid']!), + builder: + (BuildContext c, GoRouterState s) => + FamilyScreen(s.pathParameters['fid']!), routes: [ GoRoute( path: 'person/:pid', @@ -2906,10 +2986,11 @@ void main() { expect(s.pathParameters['pid'], 'p1'); return null; }, - builder: (BuildContext c, GoRouterState s) => PersonScreen( - s.pathParameters['fid']!, - s.pathParameters['pid']!, - ), + builder: + (BuildContext c, GoRouterState s) => PersonScreen( + s.pathParameters['fid']!, + s.pathParameters['pid']!, + ), ), ], ), @@ -2939,10 +3020,11 @@ void main() { final GoRouter router = await createRouter( [], tester, - redirect: (BuildContext context, GoRouterState state) => - '/${state.uri}+', - errorBuilder: (BuildContext context, GoRouterState state) => - TestErrorScreen(state.error!), + redirect: + (BuildContext context, GoRouterState state) => '/${state.uri}+', + errorBuilder: + (BuildContext context, GoRouterState state) => + TestErrorScreen(state.error!), redirectLimit: 10, ); @@ -3003,8 +3085,8 @@ void main() { GoRoute( name: 'home', path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( name: 'login', @@ -3049,19 +3131,21 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'dummy', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), redirect: (BuildContext context, GoRouterState state) => '/other', routes: [ GoRoute( path: 'dummy2', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), redirect: (BuildContext context, GoRouterState state) { assert(false); return '/other2'; @@ -3071,13 +3155,15 @@ void main() { ), GoRoute( path: 'other', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), GoRoute( path: 'other2', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), ], ), @@ -3101,25 +3187,29 @@ void main() { final List routes = [ ShellRoute( redirect: (BuildContext context, GoRouterState state) => '/dummy', - builder: (BuildContext context, GoRouterState state, Widget child) => - Scaffold(appBar: AppBar(), body: child), + builder: + (BuildContext context, GoRouterState state, Widget child) => + Scaffold(appBar: AppBar(), body: child), routes: [ GoRoute( path: '/other', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), GoRoute( path: '/other2', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), ], ), GoRoute( path: '/dummy', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), ]; @@ -3153,8 +3243,9 @@ void main() { routes: [ GoRoute( path: '/other', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), ], ), @@ -3162,8 +3253,9 @@ void main() { routes: [ GoRoute( path: '/other2', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), ], ), @@ -3171,8 +3263,9 @@ void main() { ), GoRoute( path: '/dummy', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), ]; @@ -3194,13 +3287,14 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'dummy', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), ], ), @@ -3221,8 +3315,8 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'dummy', @@ -3251,8 +3345,8 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/dummy', @@ -3273,18 +3367,22 @@ void main() { 'does not take precedence over platformDispatcher.defaultRouteName', (WidgetTester tester) async { TestWidgetsFlutterBinding - .instance.platformDispatcher.defaultRouteNameTestValue = '/dummy'; + .instance + .platformDispatcher + .defaultRouteNameTestValue = '/dummy'; final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => + const HomeScreen(), routes: [ GoRoute( path: 'dummy', - builder: (BuildContext context, GoRouterState state) => - const DummyScreen(), + builder: + (BuildContext context, GoRouterState state) => + const DummyScreen(), ), ], ), @@ -3315,8 +3413,8 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), ]; @@ -3324,7 +3422,9 @@ void main() { 'When platformDispatcher.defaultRouteName is deep-link Uri with ' 'scheme, authority, no path', (WidgetTester tester) async { - TestWidgetsFlutterBinding.instance.platformDispatcher + TestWidgetsFlutterBinding + .instance + .platformDispatcher .defaultRouteNameTestValue = 'https://domain.com'; final GoRouter router = await createRouter(routes, tester); expect(router.routeInformationProvider.value.uri.path, '/'); @@ -3337,7 +3437,9 @@ void main() { 'When platformDispatcher.defaultRouteName is deep-link Uri with ' 'scheme, authority, no path, but trailing slash', (WidgetTester tester) async { - TestWidgetsFlutterBinding.instance.platformDispatcher + TestWidgetsFlutterBinding + .instance + .platformDispatcher .defaultRouteNameTestValue = 'https://domain.com/'; final GoRouter router = await createRouter(routes, tester); expect(router.routeInformationProvider.value.uri.path, '/'); @@ -3350,7 +3452,9 @@ void main() { 'When platformDispatcher.defaultRouteName is deep-link Uri with ' 'scheme, authority, no path, and query parameters', (WidgetTester tester) async { - TestWidgetsFlutterBinding.instance.platformDispatcher + TestWidgetsFlutterBinding + .instance + .platformDispatcher .defaultRouteNameTestValue = 'https://domain.com?param=1'; final GoRouter router = await createRouter(routes, tester); expect( @@ -3368,13 +3472,14 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/family/:fid', - builder: (BuildContext context, GoRouterState state) => - FamilyScreen(state.pathParameters['fid']!), + builder: + (BuildContext context, GoRouterState state) => + FamilyScreen(state.pathParameters['fid']!), ), ]; @@ -3397,13 +3502,14 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/family', - builder: (BuildContext context, GoRouterState state) => - FamilyScreen(state.uri.queryParameters['fid']!), + builder: + (BuildContext context, GoRouterState state) => + FamilyScreen(state.uri.queryParameters['fid']!), ), ]; @@ -3484,8 +3590,9 @@ void main() { routes: [ GoRoute(path: '/:id/:blah/:bam/:id/:blah', builder: dummy), ], - errorBuilder: (BuildContext context, GoRouterState state) => - TestErrorScreen(state.error!), + errorBuilder: + (BuildContext context, GoRouterState state) => + TestErrorScreen(state.error!), initialLocation: '/0/1/2/0/1', ); expect(false, true); @@ -3542,15 +3649,17 @@ void main() { GoRoute(path: '/', builder: dummy), GoRoute( path: '/family', - builder: (BuildContext context, GoRouterState state) => - FamilyScreen(state.uri.queryParameters['fid']!), + builder: + (BuildContext context, GoRouterState state) => + FamilyScreen(state.uri.queryParameters['fid']!), ), GoRoute( path: '/person', - builder: (BuildContext context, GoRouterState state) => PersonScreen( - state.uri.queryParameters['fid']!, - state.uri.queryParameters['pid']!, - ), + builder: + (BuildContext context, GoRouterState state) => PersonScreen( + state.uri.queryParameters['fid']!, + state.uri.queryParameters['pid']!, + ), ), ], tester); @@ -3575,15 +3684,17 @@ void main() { GoRoute(path: '/', builder: dummy), GoRoute( path: '/family', - builder: (BuildContext context, GoRouterState state) => - FamilyScreen((state.extra! as Map)['fid']!), + builder: + (BuildContext context, GoRouterState state) => + FamilyScreen((state.extra! as Map)['fid']!), ), GoRoute( path: '/person', - builder: (BuildContext context, GoRouterState state) => PersonScreen( - (state.extra! as Map)['fid']!, - (state.extra! as Map)['pid']!, - ), + builder: + (BuildContext context, GoRouterState state) => PersonScreen( + (state.extra! as Map)['fid']!, + (state.extra! as Map)['pid']!, + ), ), ], tester); @@ -3607,13 +3718,14 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( path: '/family/:fid', - builder: (BuildContext context, GoRouterState state) => - FamilyScreen(state.pathParameters['fid']!), + builder: + (BuildContext context, GoRouterState state) => + FamilyScreen(state.pathParameters['fid']!), routes: [ GoRoute( path: 'person/:pid', @@ -3665,8 +3777,9 @@ void main() { routes: [ GoRoute( path: '/a', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen A'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen A'), ), ], ), @@ -3674,13 +3787,15 @@ void main() { routes: [ GoRoute( path: '/family', - builder: (BuildContext context, GoRouterState state) => - const Text('Families'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Families'), routes: [ GoRoute( path: ':fid', - builder: (BuildContext context, GoRouterState state) => - FamilyScreen(state.pathParameters['fid']!), + builder: + (BuildContext context, GoRouterState state) => + FamilyScreen(state.pathParameters['fid']!), routes: [ GoRoute( path: 'person/:pid', @@ -3757,8 +3872,9 @@ void main() { routes: [ GoRoute( path: '/a', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen A'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen A'), ), ], ), @@ -3808,8 +3924,8 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( name: 'page', @@ -3868,8 +3984,8 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( name: 'page', @@ -3919,8 +4035,8 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( name: 'page', @@ -3961,14 +4077,15 @@ void main() { GoRoute( path: '/', name: 'home', - builder: (BuildContext context, GoRouterState state) => - DummyStatefulWidget(key: key), + builder: + (BuildContext context, GoRouterState state) => + DummyStatefulWidget(key: key), ), GoRoute( path: '/page1', name: 'page1', - builder: (BuildContext context, GoRouterState state) => - const Page1Screen(), + builder: + (BuildContext context, GoRouterState state) => const Page1Screen(), ), ]; @@ -4255,8 +4372,7 @@ void main() { }, ); - testWidgets( - 'Pops from the correct navigator when a sub-route is placed on ' + testWidgets('Pops from the correct navigator when a sub-route is placed on ' 'the root Navigator', (WidgetTester tester) async { final GlobalKey rootNavigatorKey = GlobalKey(); @@ -4320,19 +4436,20 @@ void main() { final List routes = [ StatefulShellRoute.indexedStack( - builder: ( - BuildContext context, - GoRouterState state, - StatefulNavigationShell navigationShell, - ) => - navigationShell, + builder: + ( + BuildContext context, + GoRouterState state, + StatefulNavigationShell navigationShell, + ) => navigationShell, branches: [ StatefulShellBranch( routes: [ GoRoute( path: '/a', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen A'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen A'), ), ], ), @@ -4340,8 +4457,9 @@ void main() { routes: [ GoRoute( path: '/b', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen B'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen B'), ), ], ), @@ -4373,23 +4491,24 @@ void main() { final List routes = [ GoRoute( path: '/root', - builder: (BuildContext context, GoRouterState state) => - const Text('Root'), + builder: + (BuildContext context, GoRouterState state) => const Text('Root'), routes: [ StatefulShellRoute.indexedStack( - builder: ( - BuildContext context, - GoRouterState state, - StatefulNavigationShell navigationShell, - ) => - navigationShell, + builder: + ( + BuildContext context, + GoRouterState state, + StatefulNavigationShell navigationShell, + ) => navigationShell, branches: [ StatefulShellBranch( routes: [ GoRoute( path: 'a', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen A'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen A'), ), ], ), @@ -4397,8 +4516,9 @@ void main() { routes: [ GoRoute( path: 'b', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen B'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen B'), ), ], ), @@ -4447,8 +4567,9 @@ void main() { routes: [ GoRoute( path: '/a', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen A'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen A'), ), ], ), @@ -4456,8 +4577,9 @@ void main() { routes: [ GoRoute( path: '/b', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen B'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen B'), ), ], ), @@ -4465,8 +4587,9 @@ void main() { routes: [ GoRoute( path: '/c', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen C'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen C'), ), ], ), @@ -4474,8 +4597,9 @@ void main() { routes: [ GoRoute( path: '/d', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen D'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen D'), ), ], ), @@ -4548,18 +4672,20 @@ void main() { routes: [ GoRoute( path: '/a', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen A'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen A'), routes: [ GoRoute( path: 'detailA', - builder: (BuildContext context, GoRouterState state) => - Column( - children: [ - const Text('Screen A Detail'), - DummyStatefulWidget(key: statefulWidgetKey), - ], - ), + builder: + (BuildContext context, GoRouterState state) => + Column( + children: [ + const Text('Screen A Detail'), + DummyStatefulWidget(key: statefulWidgetKey), + ], + ), ), ], ), @@ -4569,8 +4695,9 @@ void main() { routes: [ GoRoute( path: '/b', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen B'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen B'), ), ], ), @@ -4634,8 +4761,9 @@ void main() { routes: [ GoRoute( path: 'a', - builder: (BuildContext context, GoRouterState state) => - Text('a id is ${state.pathParameters['id']}'), + builder: + (BuildContext context, GoRouterState state) => + Text('a id is ${state.pathParameters['id']}'), ), ], ), @@ -4643,8 +4771,9 @@ void main() { routes: [ GoRoute( path: 'b', - builder: (BuildContext context, GoRouterState state) => - Text('b id is ${state.pathParameters['id']}'), + builder: + (BuildContext context, GoRouterState state) => + Text('b id is ${state.pathParameters['id']}'), ), ], ), @@ -4709,13 +4838,13 @@ void main() { builder: (BuildContext context, GoRouterState state) => Column( - children: [ - const Text('Screen A Detail'), - DummyStatefulWidget( - key: statefulWidgetKey, - ), - ], - ), + children: [ + const Text('Screen A Detail'), + DummyStatefulWidget( + key: statefulWidgetKey, + ), + ], + ), ), ], ), @@ -4749,8 +4878,9 @@ void main() { routes: [ GoRoute( path: '/d', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen D'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen D'), ), ], ), @@ -4816,13 +4946,15 @@ void main() { routes: [ GoRoute( path: '/a', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen A'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen A'), routes: [ GoRoute( path: 'detailA', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen A Detail'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen A Detail'), ), ], ), @@ -4833,13 +4965,15 @@ void main() { routes: [ GoRoute( path: '/b', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen B'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen B'), routes: [ GoRoute( path: 'detailB', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen B Detail'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen B Detail'), ), ], ), @@ -4888,8 +5022,7 @@ void main() { }, ); - testWidgets( - 'Maintains extra navigation information when navigating ' + testWidgets('Maintains extra navigation information when navigating ' 'between branches in StatefulShellRoute', (WidgetTester tester) async { final GlobalKey rootNavigatorKey = GlobalKey(); @@ -4910,8 +5043,9 @@ void main() { routes: [ GoRoute( path: '/a', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen A'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen A'), ), ], ), @@ -4919,8 +5053,9 @@ void main() { routes: [ GoRoute( path: '/b', - builder: (BuildContext context, GoRouterState state) => - Text('Screen B - ${state.extra}'), + builder: + (BuildContext context, GoRouterState state) => + Text('Screen B - ${state.extra}'), ), ], ), @@ -4952,8 +5087,7 @@ void main() { expect(find.text('Screen B - X'), findsOneWidget); }); - testWidgets( - 'Pushed non-descendant routes are correctly restored when ' + testWidgets('Pushed non-descendant routes are correctly restored when ' 'navigating between branches in StatefulShellRoute', ( WidgetTester tester, ) async { @@ -4964,8 +5098,9 @@ void main() { final List routes = [ GoRoute( path: '/common', - builder: (BuildContext context, GoRouterState state) => - Text('Common - ${state.extra}'), + builder: + (BuildContext context, GoRouterState state) => + Text('Common - ${state.extra}'), ), StatefulShellRoute.indexedStack( builder: ( @@ -4981,8 +5116,9 @@ void main() { routes: [ GoRoute( path: '/a', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen A'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen A'), ), ], ), @@ -4990,8 +5126,9 @@ void main() { routes: [ GoRoute( path: '/b', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen B'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen B'), ), ], ), @@ -5053,8 +5190,9 @@ void main() { routes: [ GoRoute( path: '/a', - builder: (BuildContext context, GoRouterState state) => - DummyStatefulWidget(key: statefulWidgetKeyA), + builder: + (BuildContext context, GoRouterState state) => + DummyStatefulWidget(key: statefulWidgetKeyA), ), ], ), @@ -5062,8 +5200,9 @@ void main() { routes: [ GoRoute( path: '/b', - builder: (BuildContext context, GoRouterState state) => - DummyStatefulWidget(key: statefulWidgetKeyB), + builder: + (BuildContext context, GoRouterState state) => + DummyStatefulWidget(key: statefulWidgetKeyB), ), ], ), @@ -5077,8 +5216,9 @@ void main() { routes: [ GoRoute( path: '/c', - builder: (BuildContext context, GoRouterState state) => - DummyStatefulWidget(key: statefulWidgetKeyC), + builder: + (BuildContext context, GoRouterState state) => + DummyStatefulWidget(key: statefulWidgetKeyC), ), ], ), @@ -5087,8 +5227,9 @@ void main() { routes: [ GoRoute( path: '/d', - builder: (BuildContext context, GoRouterState state) => - DummyStatefulWidget(key: statefulWidgetKeyD), + builder: + (BuildContext context, GoRouterState state) => + DummyStatefulWidget(key: statefulWidgetKeyD), ), ], ), @@ -5098,13 +5239,15 @@ void main() { routes: [ GoRoute( path: '/e', - builder: (BuildContext context, GoRouterState state) => - const Text('E'), + builder: + (BuildContext context, GoRouterState state) => + const Text('E'), routes: [ GoRoute( path: 'details', - builder: (BuildContext context, GoRouterState state) => - DummyStatefulWidget(key: statefulWidgetKeyE), + builder: + (BuildContext context, GoRouterState state) => + DummyStatefulWidget(key: statefulWidgetKeyE), ), ], ), @@ -5187,8 +5330,9 @@ void main() { routes: [ GoRoute( path: '/c', - builder: (BuildContext context, GoRouterState state) => - DummyStatefulWidget(key: statefulWidgetKeyC), + builder: + (BuildContext context, GoRouterState state) => + DummyStatefulWidget(key: statefulWidgetKeyC), ), ], ), @@ -5196,8 +5340,9 @@ void main() { routes: [ GoRoute( path: '/d', - builder: (BuildContext context, GoRouterState state) => - DummyStatefulWidget(key: statefulWidgetKeyD), + builder: + (BuildContext context, GoRouterState state) => + DummyStatefulWidget(key: statefulWidgetKeyD), ), ], ), @@ -5217,8 +5362,7 @@ void main() { expect(statefulWidgetKeyD.currentState?.counter, null); }); - testWidgets( - 'Redirects are correctly handled when switching branch in a ' + testWidgets('Redirects are correctly handled when switching branch in a ' 'StatefulShellRoute', (WidgetTester tester) async { final GlobalKey rootNavigatorKey = GlobalKey(); @@ -5239,8 +5383,9 @@ void main() { routes: [ GoRoute( path: '/a', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen A'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen A'), ), ], ), @@ -5248,18 +5393,21 @@ void main() { routes: [ GoRoute( path: '/b', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen B'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen B'), routes: [ GoRoute( path: 'details1', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen B Detail1'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen B Detail1'), ), GoRoute( path: 'details2', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen B Detail2'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen B Detail2'), ), ], ), @@ -5270,13 +5418,15 @@ void main() { GoRoute(path: '/c', redirect: (_, __) => '/c/main2'), GoRoute( path: '/c/main1', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen C1'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen C1'), ), GoRoute( path: '/c/main2', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen C2'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen C2'), ), ], ), @@ -5344,8 +5494,9 @@ void main() { routes: [ GoRoute( path: '/a', - builder: (BuildContext context, GoRouterState state) => - const Text('Screen A'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Screen A'), ), ], ), @@ -5353,12 +5504,12 @@ void main() { routes: [ // Second level / nested shell StatefulShellRoute.indexedStack( - builder: ( - BuildContext context, - GoRouterState state, - StatefulNavigationShell navigationShell, - ) => - navigationShell, + builder: + ( + BuildContext context, + GoRouterState state, + StatefulNavigationShell navigationShell, + ) => navigationShell, branches: [ StatefulShellBranch( routes: [ @@ -5401,8 +5552,9 @@ void main() { GoRoute( path: '/top-modal', parentNavigatorKey: rootNavigatorKey, - builder: (BuildContext context, GoRouterState state) => - const Text('Top Modal'), + builder: + (BuildContext context, GoRouterState state) => + const Text('Top Modal'), ), ]; @@ -5462,42 +5614,42 @@ void main() { GlobalKey(debugLabel: 'shell'); StatefulNavigationShell? routeState; StatefulShellBranch makeBranch(String name) => StatefulShellBranch( - navigatorKey: - GlobalKey(debugLabel: 'branch-$name'), - preload: true, - initialLocation: '/$name', - routes: [ - GoRoute( - path: '/$name', - builder: (BuildContext context, GoRouterState state) => + navigatorKey: GlobalKey(debugLabel: 'branch-$name'), + preload: true, + initialLocation: '/$name', + routes: [ + GoRoute( + path: '/$name', + builder: + (BuildContext context, GoRouterState state) => Text('Screen $name'), - ), - ], - ); + ), + ], + ); List createRoutes(bool includeCRoute) => [ - StatefulShellRoute.indexedStack( - key: statefulShellKey, - builder: ( - BuildContext context, - GoRouterState state, - StatefulNavigationShell navigationShell, - ) { - routeState = navigationShell; - return navigationShell; - }, - branches: [ - makeBranch('a'), - makeBranch('b'), - if (includeCRoute) makeBranch('c'), - ], - ), - ]; + StatefulShellRoute.indexedStack( + key: statefulShellKey, + builder: ( + BuildContext context, + GoRouterState state, + StatefulNavigationShell navigationShell, + ) { + routeState = navigationShell; + return navigationShell; + }, + branches: [ + makeBranch('a'), + makeBranch('b'), + if (includeCRoute) makeBranch('c'), + ], + ), + ]; final ValueNotifier config = ValueNotifier( - RoutingConfig(routes: createRoutes(true)), - ); + RoutingConfig(routes: createRoutes(true)), + ); addTearDown(config.dispose); await createRouterWithRoutingConfig( navigatorKey: rootNavigatorKey, @@ -6437,13 +6589,15 @@ void main() { routes: [ GoRoute( path: '/a', - builder: (BuildContext context, GoRouterState state) => - const Placeholder(), + builder: + (BuildContext context, GoRouterState state) => + const Placeholder(), ), GoRoute( path: '/b', - builder: (BuildContext context, GoRouterState state) => - const Placeholder(), + builder: + (BuildContext context, GoRouterState state) => + const Placeholder(), ), ], ), @@ -6463,13 +6617,15 @@ void main() { final List routes = [ GoRoute( path: '/abc', - builder: (BuildContext context, GoRouterState state) => - const Placeholder(), + builder: + (BuildContext context, GoRouterState state) => + const Placeholder(), ), GoRoute( path: '/bcd', - builder: (BuildContext context, GoRouterState state) => - const Placeholder(), + builder: + (BuildContext context, GoRouterState state) => + const Placeholder(), ), ]; @@ -6527,30 +6683,34 @@ void main() { GoRoute( name: 'home', path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), ), GoRoute( name: 'books', path: '/books', - builder: (BuildContext context, GoRouterState state) => - const Text('books'), + builder: + (BuildContext context, GoRouterState state) => + const Text('books'), ), GoRoute( name: 'boats', path: '/boats', - builder: (BuildContext context, GoRouterState state) => - const Text('boats'), + builder: + (BuildContext context, GoRouterState state) => + const Text('boats'), ), ShellRoute( - builder: (BuildContext context, GoRouterState state, Widget child) => - child, + builder: + (BuildContext context, GoRouterState state, Widget child) => + child, routes: [ GoRoute( name: 'tulips', path: '/tulips', - builder: (BuildContext context, GoRouterState state) => - const Text('tulips'), + builder: + (BuildContext context, GoRouterState state) => + const Text('tulips'), ), ], ), @@ -6602,23 +6762,26 @@ void main() { final List routes = [ GoRoute( path: '/', // root cannot be empty (existing assert) - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: 'child-route', - builder: (BuildContext context, GoRouterState state) => - const Text('/child-route'), + builder: + (BuildContext context, GoRouterState state) => + const Text('/child-route'), routes: [ GoRoute( path: 'grand-child-route', - builder: (BuildContext context, GoRouterState state) => - const Text('/grand-child-route'), + builder: + (BuildContext context, GoRouterState state) => + const Text('/grand-child-route'), ), GoRoute( path: 'redirected-grand-child-route', - redirect: (BuildContext context, GoRouterState state) => - '/child-route', + redirect: + (BuildContext context, GoRouterState state) => + '/child-route', ), ], ), @@ -6650,23 +6813,26 @@ void main() { final List routes = [ GoRoute( path: '/', - builder: (BuildContext context, GoRouterState state) => - const HomeScreen(), + builder: + (BuildContext context, GoRouterState state) => const HomeScreen(), routes: [ GoRoute( path: '/child-route', - builder: (BuildContext context, GoRouterState state) => - const Text('/child-route'), + builder: + (BuildContext context, GoRouterState state) => + const Text('/child-route'), routes: [ GoRoute( path: '/grand-child-route', - builder: (BuildContext context, GoRouterState state) => - const Text('/grand-child-route'), + builder: + (BuildContext context, GoRouterState state) => + const Text('/grand-child-route'), ), GoRoute( path: '/redirected-grand-child-route', - redirect: (BuildContext context, GoRouterState state) => - '/child-route', + redirect: + (BuildContext context, GoRouterState state) => + '/child-route', ), ], ), From 7d8d0d554e653abb4a00779ca0b81763241bfa04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Sasovsky?= Date: Wed, 24 Sep 2025 23:54:55 -0300 Subject: [PATCH 10/10] chore: add copyright to constants.dart --- packages/go_router/lib/src/misc/constants.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/go_router/lib/src/misc/constants.dart b/packages/go_router/lib/src/misc/constants.dart index 2a89463c3c2..e871c02182b 100644 --- a/packages/go_router/lib/src/misc/constants.dart +++ b/packages/go_router/lib/src/misc/constants.dart @@ -1,3 +1,7 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + import 'package:meta/meta.dart'; /// Symbol used as a Zone key to track the current GoRouter during redirects.