mirror of
https://github.com/flutter/packages.git
synced 2025-07-02 08:34:31 +08:00
[go_router] Expose full Uri
on GoRouterState
in GoRouterRedirect
(#5742)
A number of developers have voiced the desire to be able to know whether a `GoRouterState` is the result of a deep-link or in-app navigation from within their `GoRouter`'s `redirect` method. This can be accomplished by exposing the `Uri`'s `scheme` and `host` on the `GoRouterState`. This way, we can know whether the `GoRouterState` is the result of a deep-link by checking `state.uri.scheme != null` or `state.uri.host != null`. This PR would close [#103659](https://github.com/flutter/flutter/issues/103659#issuecomment-1865112881). No tests were broken as a result of this change, and we have added coverage for this change through new tests.
This commit is contained in:
@ -1,3 +1,7 @@
|
|||||||
|
## 13.2.0
|
||||||
|
|
||||||
|
- Exposes full `Uri` on `GoRouterState` in `GoRouterRedirect`
|
||||||
|
|
||||||
## 13.1.0
|
## 13.1.0
|
||||||
|
|
||||||
- Adds `topRoute` to `GoRouterState`
|
- Adds `topRoute` to `GoRouterState`
|
||||||
|
@ -11,10 +11,6 @@ import 'package:flutter/widgets.dart';
|
|||||||
|
|
||||||
import 'match.dart';
|
import 'match.dart';
|
||||||
|
|
||||||
// TODO(chunhtai): remove this ignore and migrate the code
|
|
||||||
// https://github.com/flutter/flutter/issues/124045.
|
|
||||||
// ignore_for_file: deprecated_member_use
|
|
||||||
|
|
||||||
/// The type of the navigation.
|
/// The type of the navigation.
|
||||||
///
|
///
|
||||||
/// This enum is used by [RouteInformationState] to denote the navigation
|
/// This enum is used by [RouteInformationState] to denote the navigation
|
||||||
@ -85,7 +81,7 @@ class GoRouteInformationProvider extends RouteInformationProvider
|
|||||||
Listenable? refreshListenable,
|
Listenable? refreshListenable,
|
||||||
}) : _refreshListenable = refreshListenable,
|
}) : _refreshListenable = refreshListenable,
|
||||||
_value = RouteInformation(
|
_value = RouteInformation(
|
||||||
location: initialLocation,
|
uri: Uri.parse(initialLocation),
|
||||||
state: RouteInformationState<void>(
|
state: RouteInformationState<void>(
|
||||||
extra: initialExtra, type: NavigatingType.go),
|
extra: initialExtra, type: NavigatingType.go),
|
||||||
),
|
),
|
||||||
@ -96,8 +92,8 @@ class GoRouteInformationProvider extends RouteInformationProvider
|
|||||||
final Listenable? _refreshListenable;
|
final Listenable? _refreshListenable;
|
||||||
|
|
||||||
static WidgetsBinding get _binding => WidgetsBinding.instance;
|
static WidgetsBinding get _binding => WidgetsBinding.instance;
|
||||||
static const RouteInformation _kEmptyRouteInformation =
|
static final RouteInformation _kEmptyRouteInformation =
|
||||||
RouteInformation(location: '');
|
RouteInformation(uri: Uri.parse(''));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void routerReportsNewRouteInformation(RouteInformation routeInformation,
|
void routerReportsNewRouteInformation(RouteInformation routeInformation,
|
||||||
@ -109,9 +105,9 @@ class GoRouteInformationProvider extends RouteInformationProvider
|
|||||||
final bool replace;
|
final bool replace;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case RouteInformationReportingType.none:
|
case RouteInformationReportingType.none:
|
||||||
if (_valueInEngine.location == routeInformation.location &&
|
if (!_valueHasChanged(
|
||||||
const DeepCollectionEquality()
|
newLocationUri: routeInformation.uri,
|
||||||
.equals(_valueInEngine.state, routeInformation.state)) {
|
newState: routeInformation.state)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
replace = _valueInEngine == _kEmptyRouteInformation;
|
replace = _valueInEngine == _kEmptyRouteInformation;
|
||||||
@ -122,10 +118,7 @@ class GoRouteInformationProvider extends RouteInformationProvider
|
|||||||
}
|
}
|
||||||
SystemNavigator.selectMultiEntryHistory();
|
SystemNavigator.selectMultiEntryHistory();
|
||||||
SystemNavigator.routeInformationUpdated(
|
SystemNavigator.routeInformationUpdated(
|
||||||
// TODO(chunhtai): remove this ignore and migrate the code
|
uri: routeInformation.uri,
|
||||||
// https://github.com/flutter/flutter/issues/124045.
|
|
||||||
// ignore: unnecessary_null_checks, unnecessary_non_null_assertion
|
|
||||||
location: routeInformation.location!,
|
|
||||||
state: routeInformation.state,
|
state: routeInformation.state,
|
||||||
replace: replace,
|
replace: replace,
|
||||||
);
|
);
|
||||||
@ -137,17 +130,16 @@ class GoRouteInformationProvider extends RouteInformationProvider
|
|||||||
RouteInformation _value;
|
RouteInformation _value;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
// TODO(chunhtai): remove this ignore once package minimum dart version is
|
|
||||||
// above 3.
|
|
||||||
// ignore: unnecessary_overrides
|
|
||||||
void notifyListeners() {
|
void notifyListeners() {
|
||||||
super.notifyListeners();
|
super.notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setValue(String location, Object state) {
|
void _setValue(String location, Object state) {
|
||||||
|
final Uri uri = Uri.parse(location);
|
||||||
|
|
||||||
final bool shouldNotify =
|
final bool shouldNotify =
|
||||||
_value.location != location || _value.state != state;
|
_valueHasChanged(newLocationUri: uri, newState: state);
|
||||||
_value = RouteInformation(location: location, state: state);
|
_value = RouteInformation(uri: Uri.parse(location), state: state);
|
||||||
if (shouldNotify) {
|
if (shouldNotify) {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
@ -235,7 +227,7 @@ class GoRouteInformationProvider extends RouteInformationProvider
|
|||||||
_value = _valueInEngine = routeInformation;
|
_value = _valueInEngine = routeInformation;
|
||||||
} else {
|
} else {
|
||||||
_value = RouteInformation(
|
_value = RouteInformation(
|
||||||
location: routeInformation.location,
|
uri: routeInformation.uri,
|
||||||
state: RouteInformationState<void>(type: NavigatingType.go),
|
state: RouteInformationState<void>(type: NavigatingType.go),
|
||||||
);
|
);
|
||||||
_valueInEngine = _kEmptyRouteInformation;
|
_valueInEngine = _kEmptyRouteInformation;
|
||||||
@ -243,6 +235,19 @@ class GoRouteInformationProvider extends RouteInformationProvider
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _valueHasChanged(
|
||||||
|
{required Uri newLocationUri, required Object? newState}) {
|
||||||
|
const DeepCollectionEquality deepCollectionEquality =
|
||||||
|
DeepCollectionEquality();
|
||||||
|
return !deepCollectionEquality.equals(
|
||||||
|
_value.uri.path, newLocationUri.path) ||
|
||||||
|
!deepCollectionEquality.equals(
|
||||||
|
_value.uri.queryParameters, newLocationUri.queryParameters) ||
|
||||||
|
!deepCollectionEquality.equals(
|
||||||
|
_value.uri.fragment, newLocationUri.fragment) ||
|
||||||
|
!deepCollectionEquality.equals(_value.state, newState);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void addListener(VoidCallback listener) {
|
void addListener(VoidCallback listener) {
|
||||||
if (!hasListeners) {
|
if (!hasListeners) {
|
||||||
@ -274,11 +279,4 @@ class GoRouteInformationProvider extends RouteInformationProvider
|
|||||||
_platformReportsNewRouteInformation(routeInformation);
|
_platformReportsNewRouteInformation(routeInformation);
|
||||||
return SynchronousFuture<bool>(true);
|
return SynchronousFuture<bool>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<bool> didPushRoute(String route) {
|
|
||||||
assert(hasListeners);
|
|
||||||
_platformReportsNewRouteInformation(RouteInformation(location: route));
|
|
||||||
return SynchronousFuture<bool>(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -79,19 +79,13 @@ class GoRouteInformationParser extends RouteInformationParser<RouteMatchList> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
late final RouteMatchList initialMatches;
|
late final RouteMatchList initialMatches;
|
||||||
initialMatches =
|
initialMatches = configuration.findMatch(
|
||||||
// TODO(chunhtai): remove this ignore and migrate the code
|
routeInformation.uri.path.isEmpty
|
||||||
// https://github.com/flutter/flutter/issues/124045.
|
? '${routeInformation.uri}/'
|
||||||
// TODO(chunhtai): After the migration from routeInformation's location
|
: routeInformation.uri.toString(),
|
||||||
// to uri, empty path check might be required here; see
|
extra: state.extra);
|
||||||
// https://github.com/flutter/packages/pull/5113#discussion_r1374861070
|
|
||||||
// ignore: deprecated_member_use, unnecessary_non_null_assertion
|
|
||||||
configuration.findMatch(routeInformation.location!, extra: state.extra);
|
|
||||||
if (initialMatches.isError) {
|
if (initialMatches.isError) {
|
||||||
// TODO(chunhtai): remove this ignore and migrate the code
|
log('No initial matches: ${routeInformation.uri.path}');
|
||||||
// https://github.com/flutter/flutter/issues/124045.
|
|
||||||
// ignore: deprecated_member_use
|
|
||||||
log('No initial matches: ${routeInformation.location}');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return debugParserFuture = _redirect(
|
return debugParserFuture = _redirect(
|
||||||
@ -142,10 +136,7 @@ class GoRouteInformationParser extends RouteInformationParser<RouteMatchList> {
|
|||||||
location = configuration.uri.toString();
|
location = configuration.uri.toString();
|
||||||
}
|
}
|
||||||
return RouteInformation(
|
return RouteInformation(
|
||||||
// TODO(chunhtai): remove this ignore and migrate the code
|
uri: Uri.parse(location),
|
||||||
// https://github.com/flutter/flutter/issues/124045.
|
|
||||||
// ignore: deprecated_member_use
|
|
||||||
location: location,
|
|
||||||
state: _routeMatchListCodec.encode(configuration),
|
state: _routeMatchListCodec.encode(configuration),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'misc/errors.dart';
|
||||||
import 'route.dart';
|
import 'route.dart';
|
||||||
|
|
||||||
final RegExp _parameterRegExp = RegExp(r':(\w+)(\((?:\\.|[^\\()])+\))?');
|
final RegExp _parameterRegExp = RegExp(r':(\w+)(\((?:\\.|[^\\()])+\))?');
|
||||||
@ -120,6 +121,9 @@ String concatenatePaths(String parentPath, String childPath) {
|
|||||||
|
|
||||||
/// Normalizes the location string.
|
/// Normalizes the location string.
|
||||||
String canonicalUri(String loc) {
|
String canonicalUri(String loc) {
|
||||||
|
if (loc.isEmpty) {
|
||||||
|
throw GoException('Location cannot be empty.');
|
||||||
|
}
|
||||||
String canon = Uri.parse(loc).toString();
|
String canon = Uri.parse(loc).toString();
|
||||||
canon = canon.endsWith('?') ? canon.substring(0, canon.length - 1) : canon;
|
canon = canon.endsWith('?') ? canon.substring(0, canon.length - 1) : canon;
|
||||||
|
|
||||||
@ -131,9 +135,18 @@ String canonicalUri(String loc) {
|
|||||||
? canon.substring(0, canon.length - 1)
|
? canon.substring(0, canon.length - 1)
|
||||||
: canon;
|
: canon;
|
||||||
|
|
||||||
|
// replace '/?', except for first occurrence, from path only
|
||||||
// /login/?from=/ => /login?from=/
|
// /login/?from=/ => /login?from=/
|
||||||
// /?from=/ => /?from=/
|
// /?from=/ => /?from=/
|
||||||
canon = canon.replaceFirst('/?', '?', 1);
|
final Uri uri = Uri.parse(canon);
|
||||||
|
final int pathStartIndex = uri.host.isNotEmpty
|
||||||
|
? uri.toString().indexOf(uri.host) + uri.host.length
|
||||||
|
: uri.hasScheme
|
||||||
|
? uri.toString().indexOf(uri.scheme) + uri.scheme.length
|
||||||
|
: 0;
|
||||||
|
if (pathStartIndex < canon.length) {
|
||||||
|
canon = canon.replaceFirst('/?', '?', pathStartIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
return canon;
|
return canon;
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
name: go_router
|
name: go_router
|
||||||
description: A declarative router for Flutter based on Navigation 2 supporting
|
description: A declarative router for Flutter based on Navigation 2 supporting
|
||||||
deep linking, data-driven routes and more
|
deep linking, data-driven routes and more
|
||||||
version: 13.1.0
|
version: 13.2.0
|
||||||
repository: https://github.com/flutter/packages/tree/main/packages/go_router
|
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
|
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.0.0 <4.0.0"
|
sdk: ">=3.1.0 <4.0.0"
|
||||||
flutter: ">=3.10.0"
|
flutter: ">=3.13.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
collection: ^1.15.0
|
collection: ^1.15.0
|
||||||
|
@ -258,6 +258,95 @@ void main() {
|
|||||||
expect(find.byType(DummyScreen), findsOneWidget);
|
expect(find.byType(DummyScreen), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'match top level route when location has scheme/host and has trailing /',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final List<GoRoute> routes = <GoRoute>[
|
||||||
|
GoRoute(
|
||||||
|
path: '/',
|
||||||
|
builder: (BuildContext context, GoRouterState state) =>
|
||||||
|
const HomeScreen(),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
final GoRouter router = await createRouter(routes, tester);
|
||||||
|
router.go('https://www.domain.com/?bar=baz');
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
final List<RouteMatchBase> matches =
|
||||||
|
router.routerDelegate.currentConfiguration.matches;
|
||||||
|
expect(matches, hasLength(1));
|
||||||
|
expect(matches.first.matchedLocation, '/');
|
||||||
|
expect(find.byType(HomeScreen), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'match top level route when location has scheme/host and has trailing / (2)',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final List<GoRoute> routes = <GoRoute>[
|
||||||
|
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);
|
||||||
|
router.go('https://www.domain.com/login/');
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
final List<RouteMatchBase> matches =
|
||||||
|
router.routerDelegate.currentConfiguration.matches;
|
||||||
|
expect(matches, hasLength(1));
|
||||||
|
expect(matches.first.matchedLocation, '/login');
|
||||||
|
expect(find.byType(LoginScreen), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'match top level route when location has scheme/host and has trailing / (3)',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final List<GoRoute> routes = <GoRoute>[
|
||||||
|
GoRoute(
|
||||||
|
path: '/profile',
|
||||||
|
builder: dummy,
|
||||||
|
redirect: (_, __) => '/profile/foo'),
|
||||||
|
GoRoute(path: '/profile/:kind', builder: dummy),
|
||||||
|
];
|
||||||
|
|
||||||
|
final GoRouter router = await createRouter(routes, tester);
|
||||||
|
router.go('https://www.domain.com/profile/');
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
final List<RouteMatchBase> matches =
|
||||||
|
router.routerDelegate.currentConfiguration.matches;
|
||||||
|
expect(matches, hasLength(1));
|
||||||
|
expect(matches.first.matchedLocation, '/profile/foo');
|
||||||
|
expect(find.byType(DummyScreen), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'match top level route when location has scheme/host and has trailing / (4)',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
final List<GoRoute> routes = <GoRoute>[
|
||||||
|
GoRoute(
|
||||||
|
path: '/profile',
|
||||||
|
builder: dummy,
|
||||||
|
redirect: (_, __) => '/profile/foo'),
|
||||||
|
GoRoute(path: '/profile/:kind', builder: dummy),
|
||||||
|
];
|
||||||
|
|
||||||
|
final GoRouter router = await createRouter(routes, tester);
|
||||||
|
router.go('https://www.domain.com/profile/?bar=baz');
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
final List<RouteMatchBase> matches =
|
||||||
|
router.routerDelegate.currentConfiguration.matches;
|
||||||
|
expect(matches, hasLength(1));
|
||||||
|
expect(matches.first.matchedLocation, '/profile/foo');
|
||||||
|
expect(find.byType(DummyScreen), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('repeatedly pops imperative route does not crash',
|
testWidgets('repeatedly pops imperative route does not crash',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
// Regression test for https://github.com/flutter/flutter/issues/123369.
|
// Regression test for https://github.com/flutter/flutter/issues/123369.
|
||||||
@ -1301,10 +1390,7 @@ void main() {
|
|||||||
expect(find.byKey(const ValueKey<String>('home')), findsOneWidget);
|
expect(find.byKey(const ValueKey<String>('home')), findsOneWidget);
|
||||||
|
|
||||||
router.routeInformationProvider.didPushRouteInformation(
|
router.routeInformationProvider.didPushRouteInformation(
|
||||||
// TODO(chunhtai): remove this ignore and migrate the code
|
RouteInformation(uri: Uri.parse(location), state: state));
|
||||||
// https://github.com/flutter/flutter/issues/124045.
|
|
||||||
// ignore: deprecated_member_use
|
|
||||||
RouteInformation(location: location, state: state));
|
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
// Make sure it has all the imperative routes.
|
// Make sure it has all the imperative routes.
|
||||||
expect(find.byKey(const ValueKey<String>('settings-1')), findsOneWidget);
|
expect(find.byKey(const ValueKey<String>('settings-1')), findsOneWidget);
|
||||||
@ -2435,10 +2521,7 @@ void main() {
|
|||||||
routes,
|
routes,
|
||||||
tester,
|
tester,
|
||||||
);
|
);
|
||||||
// TODO(chunhtai): remove this ignore and migrate the code
|
expect(router.routeInformationProvider.value.uri.path, '/dummy');
|
||||||
// https://github.com/flutter/flutter/issues/124045.
|
|
||||||
// ignore: deprecated_member_use
|
|
||||||
expect(router.routeInformationProvider.value.location, '/dummy');
|
|
||||||
TestWidgetsFlutterBinding.instance.platformDispatcher
|
TestWidgetsFlutterBinding.instance.platformDispatcher
|
||||||
.clearDefaultRouteNameTestValue();
|
.clearDefaultRouteNameTestValue();
|
||||||
});
|
});
|
||||||
|
@ -26,11 +26,46 @@ void main() {
|
|||||||
GoRouteInformationProvider(
|
GoRouteInformationProvider(
|
||||||
initialLocation: initialRoute, initialExtra: null);
|
initialLocation: initialRoute, initialExtra: null);
|
||||||
provider.addListener(expectAsync0(() {}));
|
provider.addListener(expectAsync0(() {}));
|
||||||
// TODO(chunhtai): remove this ignore and migrate the code
|
|
||||||
// https://github.com/flutter/flutter/issues/124045.
|
|
||||||
// ignore_for_file: deprecated_member_use
|
|
||||||
provider
|
provider
|
||||||
.didPushRouteInformation(const RouteInformation(location: newRoute));
|
.didPushRouteInformation(RouteInformation(uri: Uri.parse(newRoute)));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('didPushRouteInformation maintains uri scheme and host',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
const String expectedScheme = 'https';
|
||||||
|
const String expectedHost = 'www.example.com';
|
||||||
|
const String expectedPath = '/some/path';
|
||||||
|
const String expectedUriString =
|
||||||
|
'$expectedScheme://$expectedHost$expectedPath';
|
||||||
|
late final GoRouteInformationProvider provider =
|
||||||
|
GoRouteInformationProvider(
|
||||||
|
initialLocation: initialRoute, initialExtra: null);
|
||||||
|
provider.addListener(expectAsync0(() {}));
|
||||||
|
provider.didPushRouteInformation(
|
||||||
|
RouteInformation(uri: Uri.parse(expectedUriString)));
|
||||||
|
expect(provider.value.uri.scheme, 'https');
|
||||||
|
expect(provider.value.uri.host, 'www.example.com');
|
||||||
|
expect(provider.value.uri.path, '/some/path');
|
||||||
|
expect(provider.value.uri.toString(), expectedUriString);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('didPushRoute maintains uri scheme and host',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
const String expectedScheme = 'https';
|
||||||
|
const String expectedHost = 'www.example.com';
|
||||||
|
const String expectedPath = '/some/path';
|
||||||
|
const String expectedUriString =
|
||||||
|
'$expectedScheme://$expectedHost$expectedPath';
|
||||||
|
late final GoRouteInformationProvider provider =
|
||||||
|
GoRouteInformationProvider(
|
||||||
|
initialLocation: initialRoute, initialExtra: null);
|
||||||
|
provider.addListener(expectAsync0(() {}));
|
||||||
|
provider.didPushRouteInformation(
|
||||||
|
RouteInformation(uri: Uri.parse(expectedUriString)));
|
||||||
|
expect(provider.value.uri.scheme, 'https');
|
||||||
|
expect(provider.value.uri.host, 'www.example.com');
|
||||||
|
expect(provider.value.uri.path, '/some/path');
|
||||||
|
expect(provider.value.uri.toString(), expectedUriString);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,7 @@ import 'test_helpers.dart';
|
|||||||
|
|
||||||
RouteInformation createRouteInformation(String location, [Object? extra]) {
|
RouteInformation createRouteInformation(String location, [Object? extra]) {
|
||||||
return RouteInformation(
|
return RouteInformation(
|
||||||
// TODO(chunhtai): remove this ignore and migrate the code
|
uri: Uri.parse(location),
|
||||||
// https://github.com/flutter/flutter/issues/124045.
|
|
||||||
// ignore: deprecated_member_use
|
|
||||||
location: location,
|
|
||||||
state:
|
state:
|
||||||
RouteInformationState<void>(type: NavigatingType.go, extra: extra));
|
RouteInformationState<void>(type: NavigatingType.go, extra: extra));
|
||||||
}
|
}
|
||||||
@ -83,6 +80,52 @@ void main() {
|
|||||||
expect(matches[1].route, routes[0].routes[0]);
|
expect(matches[1].route, routes[0].routes[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
"GoRouteInformationParser can parse deeplink route and maintain uri's scheme and host",
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
const String expectedScheme = 'https';
|
||||||
|
const String expectedHost = 'www.example.com';
|
||||||
|
const String expectedPath = '/abc';
|
||||||
|
const String expectedUriString =
|
||||||
|
'$expectedScheme://$expectedHost$expectedPath';
|
||||||
|
final List<GoRoute> routes = <GoRoute>[
|
||||||
|
GoRoute(
|
||||||
|
path: '/',
|
||||||
|
builder: (_, __) => const Placeholder(),
|
||||||
|
routes: <GoRoute>[
|
||||||
|
GoRoute(
|
||||||
|
path: 'abc',
|
||||||
|
builder: (_, __) => const Placeholder(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
];
|
||||||
|
final GoRouteInformationParser parser = await createParser(
|
||||||
|
tester,
|
||||||
|
routes: routes,
|
||||||
|
redirectLimit: 100,
|
||||||
|
redirect: (_, __) => null,
|
||||||
|
);
|
||||||
|
|
||||||
|
final BuildContext context = tester.element(find.byType(Router<Object>));
|
||||||
|
|
||||||
|
final RouteMatchList matchesObj =
|
||||||
|
await parser.parseRouteInformationWithDependencies(
|
||||||
|
createRouteInformation(expectedUriString), context);
|
||||||
|
final List<RouteMatchBase> matches = matchesObj.matches;
|
||||||
|
expect(matches.length, 2);
|
||||||
|
expect(matchesObj.uri.toString(), expectedUriString);
|
||||||
|
expect(matchesObj.uri.scheme, expectedScheme);
|
||||||
|
expect(matchesObj.uri.host, expectedHost);
|
||||||
|
expect(matchesObj.uri.path, expectedPath);
|
||||||
|
|
||||||
|
expect(matches[0].matchedLocation, '/');
|
||||||
|
expect(matches[0].route, routes[0]);
|
||||||
|
|
||||||
|
expect(matches[1].matchedLocation, '/abc');
|
||||||
|
expect(matches[1].route, routes[0].routes[0]);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'GoRouteInformationParser can restore full route matches if optionURLReflectsImperativeAPIs is true',
|
'GoRouteInformationParser can restore full route matches if optionURLReflectsImperativeAPIs is true',
|
||||||
(WidgetTester tester) async {
|
(WidgetTester tester) async {
|
||||||
@ -114,11 +157,7 @@ void main() {
|
|||||||
|
|
||||||
final RouteInformation restoredRouteInformation =
|
final RouteInformation restoredRouteInformation =
|
||||||
router.routeInformationParser.restoreRouteInformation(matchList)!;
|
router.routeInformationParser.restoreRouteInformation(matchList)!;
|
||||||
// URL reflects the latest push.
|
expect(restoredRouteInformation.uri.path, '/');
|
||||||
// TODO(chunhtai): remove this ignore and migrate the code
|
|
||||||
// https://github.com/flutter/flutter/issues/124045.
|
|
||||||
// ignore: deprecated_member_use
|
|
||||||
expect(restoredRouteInformation.location, '/');
|
|
||||||
|
|
||||||
// Can restore back to original RouteMatchList.
|
// Can restore back to original RouteMatchList.
|
||||||
final RouteMatchList parsedRouteMatch = await router.routeInformationParser
|
final RouteMatchList parsedRouteMatch = await router.routeInformationParser
|
||||||
|
Reference in New Issue
Block a user