Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions packages/go_router/lib/src/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import 'misc/constants.dart';
import 'misc/inherited_router.dart';
import 'on_enter.dart';
import 'parser.dart';
import 'path_utils.dart';
import 'route.dart';
import 'state.dart';

Expand Down Expand Up @@ -402,11 +403,24 @@ class GoRouter implements RouterConfig<RouteMatchList> {
fragment: fragment,
);

String _resolveRelativeLocation(String location) {
if (!location.startsWith('./')) {
return location;
}
Comment thread
Boulea7 marked this conversation as resolved.

final RouteMatch? lastMatch = routerDelegate.currentConfiguration.lastOrNull;
if (lastMatch is! ImperativeRouteMatch) {
return location;
}

return concatenateUris(lastMatch.matches.uri, Uri.parse(location)).toString();
}

/// Navigate to a URI location w/ optional query parameters, e.g.
/// `/family/f2/person/p1?color=blue`
void go(String location, {Object? extra}) {
log('going to $location');
routeInformationProvider.go(location, extra: extra);
routeInformationProvider.go(_resolveRelativeLocation(location), extra: extra);
}

/// Restore the RouteMatchList
Expand Down Expand Up @@ -448,7 +462,7 @@ class GoRouter implements RouterConfig<RouteMatchList> {
Future<T?> push<T extends Object?>(String location, {Object? extra}) async {
log('pushing $location');
return routeInformationProvider.push<T>(
location,
_resolveRelativeLocation(location),
base: routerDelegate.currentConfiguration,
extra: extra,
);
Expand Down Expand Up @@ -478,7 +492,7 @@ class GoRouter implements RouterConfig<RouteMatchList> {
Future<T?> pushReplacement<T extends Object?>(String location, {Object? extra}) {
log('pushReplacement $location');
return routeInformationProvider.pushReplacement<T>(
location,
_resolveRelativeLocation(location),
base: routerDelegate.currentConfiguration,
extra: extra,
);
Expand Down Expand Up @@ -516,7 +530,7 @@ class GoRouter implements RouterConfig<RouteMatchList> {
Future<T?> replace<T>(String location, {Object? extra}) {
log('replace $location');
return routeInformationProvider.replace<T>(
location,
_resolveRelativeLocation(location),
base: routerDelegate.currentConfiguration,
extra: extra,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
changelog: |
- Fixes relative navigation resolving against the underlying route instead of the imperatively-pushed route.
version: patch
53 changes: 53 additions & 0 deletions packages/go_router/test/imperative_api_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -286,4 +286,57 @@ void main() {
expect(find.text('shell'), findsNothing);
expect(find.byKey(e), findsOneWidget);
});

for (final MapEntry<String, void Function(GoRouter, String)> operation
in <String, void Function(GoRouter, String)>{
'go': (GoRouter router, String location) => router.go(location),
'push': (GoRouter router, String location) => router.push<void>(location),
'pushReplacement': (GoRouter router, String location) =>
router.pushReplacement<void>(location),
'replace': (GoRouter router, String location) => router.replace<void>(location),
}.entries) {
testWidgets('${operation.key} resolves a relative route against the imperative top', (
WidgetTester tester,
) async {
// Regression test for https://github.com/flutter/flutter/issues/182441.
final homeReviews = UniqueKey();
final productReviews = UniqueKey();
final routes = <RouteBase>[
GoRoute(
path: '/home',
builder: (_, _) => const DummyScreen(),
routes: <RouteBase>[
GoRoute(
path: 'reviews',
builder: (_, _) => DummyScreen(key: homeReviews),
),
],
),
GoRoute(
path: '/products/:id',
builder: (_, _) => const DummyScreen(),
routes: <RouteBase>[
GoRoute(
path: 'reviews',
builder: (_, _) => DummyScreen(key: productReviews),
),
],
),
];
final GoRouter router = await createRouter(routes, tester, initialLocation: '/home');

router.push<void>('/products/9');
await tester.pumpAndSettle();
expect(router.state.uri.path, '/products/9');

operation.value(router, './reviews?sort=recent#top');
await tester.pumpAndSettle();

expect(router.state.uri.path, '/products/9/reviews');
expect(router.state.uri.queryParameters, <String, String>{'sort': 'recent'});
expect(router.state.uri.fragment, 'top');
expect(find.byKey(productReviews), findsOneWidget);
expect(find.byKey(homeReviews), findsNothing);
});
}
}