Unverified Commit 3b4ac4d5 authored by chunhtai's avatar chunhtai Committed by GitHub

Implement url support for RouteInformation and didPushRouteInformation (#119968)

Related https://github.com/flutter/flutter/issues/100624

The goal is to make sure the engine can send a location string in either the existing format or a complete uri string to the framework, and the framework will still work as usual.
parent 034adb66
...@@ -80,14 +80,21 @@ abstract final class SystemNavigator { ...@@ -80,14 +80,21 @@ abstract final class SystemNavigator {
/// ///
/// The `replace` flag defaults to false. /// The `replace` flag defaults to false.
static Future<void> routeInformationUpdated({ static Future<void> routeInformationUpdated({
required String location, @Deprecated(
'Pass Uri.parse(location) to uri parameter instead. '
'This feature was deprecated after v3.8.0-3.0.pre.'
)
String? location,
Uri? uri,
Object? state, Object? state,
bool replace = false, bool replace = false,
}) { }) {
assert((location != null) != (uri != null), 'One of uri or location must be provided, but not both.');
uri ??= Uri.parse(location!);
return SystemChannels.navigation.invokeMethod<void>( return SystemChannels.navigation.invokeMethod<void>(
'routeInformationUpdated', 'routeInformationUpdated',
<String, dynamic>{ <String, dynamic>{
'location': location, 'uri': uri.toString(),
'state': state, 'state': state,
'replace': replace, 'replace': replace,
}, },
......
...@@ -1362,7 +1362,7 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver { ...@@ -1362,7 +1362,7 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
if (widget.routeInformationProvider == null && widget.routeInformationParser != null) { if (widget.routeInformationProvider == null && widget.routeInformationParser != null) {
_defaultRouteInformationProvider ??= PlatformRouteInformationProvider( _defaultRouteInformationProvider ??= PlatformRouteInformationProvider(
initialRouteInformation: RouteInformation( initialRouteInformation: RouteInformation(
location: _initialRouteName, uri: Uri.parse(_initialRouteName),
), ),
); );
} else { } else {
...@@ -1484,7 +1484,7 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver { ...@@ -1484,7 +1484,7 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
} }
@override @override
Future<bool> didPushRoute(String route) async { Future<bool> didPushRouteInformation(RouteInformation routeInformation) async {
assert(mounted); assert(mounted);
// The route name provider should handle the push route if we uses a // The route name provider should handle the push route if we uses a
// router. // router.
...@@ -1496,7 +1496,16 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver { ...@@ -1496,7 +1496,16 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
if (navigator == null) { if (navigator == null) {
return false; return false;
} }
navigator.pushNamed(route); final Uri uri = routeInformation.uri;
navigator.pushNamed(
Uri.decodeComponent(
Uri(
path: uri.path.isEmpty ? '/' : uri.path,
queryParameters: uri.queryParametersAll.isEmpty ? null : uri.queryParametersAll,
fragment: uri.fragment.isEmpty ? null : uri.fragment,
).toString(),
),
);
return true; return true;
} }
......
...@@ -72,6 +72,10 @@ abstract mixin class WidgetsBindingObserver { ...@@ -72,6 +72,10 @@ abstract mixin class WidgetsBindingObserver {
/// ///
/// This method exposes the `pushRoute` notification from /// This method exposes the `pushRoute` notification from
/// [SystemChannels.navigation]. /// [SystemChannels.navigation].
@Deprecated(
'Use didPushRouteInformation instead. '
'This feature was deprecated after v3.8.0-14.0.pre.'
)
Future<bool> didPushRoute(String route) => Future<bool>.value(false); Future<bool> didPushRoute(String route) => Future<bool>.value(false);
/// Called when the host tells the application to push a new /// Called when the host tells the application to push a new
...@@ -85,9 +89,20 @@ abstract mixin class WidgetsBindingObserver { ...@@ -85,9 +89,20 @@ abstract mixin class WidgetsBindingObserver {
/// [SystemChannels.navigation]. /// [SystemChannels.navigation].
/// ///
/// The default implementation is to call the [didPushRoute] directly with the /// The default implementation is to call the [didPushRoute] directly with the
/// [RouteInformation.location]. /// string constructed from [RouteInformation.uri]'s path and query parameters.
// TODO(chunhtai): remove the default implementation once `didPushRoute` is
// removed.
Future<bool> didPushRouteInformation(RouteInformation routeInformation) { Future<bool> didPushRouteInformation(RouteInformation routeInformation) {
return didPushRoute(routeInformation.location!); final Uri uri = routeInformation.uri;
return didPushRoute(
Uri.decodeComponent(
Uri(
path: uri.path.isEmpty ? '/' : uri.path,
queryParameters: uri.queryParametersAll.isEmpty ? null : uri.queryParametersAll,
fragment: uri.fragment.isEmpty ? null : uri.fragment,
).toString(),
),
);
} }
/// Called when the application's dimensions change. For example, /// Called when the application's dimensions change. For example,
...@@ -672,23 +687,21 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB ...@@ -672,23 +687,21 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
@protected @protected
@mustCallSuper @mustCallSuper
Future<void> handlePushRoute(String route) async { Future<void> handlePushRoute(String route) async {
final RouteInformation routeInformation = RouteInformation(uri: Uri.parse(route));
for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.of(_observers)) { for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.of(_observers)) {
if (await observer.didPushRoute(route)) { if (await observer.didPushRouteInformation(routeInformation)) {
return; return;
} }
} }
} }
Future<void> _handlePushRouteInformation(Map<dynamic, dynamic> routeArguments) async { Future<void> _handlePushRouteInformation(Map<dynamic, dynamic> routeArguments) async {
for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.of(_observers)) { final RouteInformation routeInformation = RouteInformation(
if ( uri: Uri.parse(routeArguments['location'] as String),
await observer.didPushRouteInformation(
RouteInformation(
location: routeArguments['location'] as String,
state: routeArguments['state'] as Object?, state: routeArguments['state'] as Object?,
), );
) for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.of(_observers)) {
) { if (await observer.didPushRouteInformation(routeInformation)) {
return; return;
} }
} }
......
...@@ -4050,7 +4050,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res ...@@ -4050,7 +4050,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
); );
final String? routeName = lastEntry?.route.settings.name; final String? routeName = lastEntry?.route.settings.name;
if (routeName != null && routeName != _lastAnnouncedRouteName) { if (routeName != null && routeName != _lastAnnouncedRouteName) {
SystemNavigator.routeInformationUpdated(location: routeName); SystemNavigator.routeInformationUpdated(uri: Uri.parse(routeName));
_lastAnnouncedRouteName = routeName; _lastAnnouncedRouteName = routeName;
} }
} }
......
...@@ -41,18 +41,57 @@ import 'restoration_properties.dart'; ...@@ -41,18 +41,57 @@ import 'restoration_properties.dart';
class RouteInformation { class RouteInformation {
/// Creates a route information object. /// Creates a route information object.
/// ///
/// The arguments may be null. /// Either location or uri must not be null.
const RouteInformation({this.location, this.state}); const RouteInformation({
@Deprecated(
'Pass Uri.parse(location) to uri parameter instead. '
'This feature was deprecated after v3.8.0-3.0.pre.'
)
String? location,
Uri? uri,
this.state,
}) : _location = location,
_uri = uri,
assert((location != null) != (uri != null));
/// The location of the application. /// The location of the application.
/// ///
/// The string is usually in the format of multiple string identifiers with /// The string is usually in the format of multiple string identifiers with
/// slashes in between. ex: `/`, `/path`, `/path/to/the/app`. /// slashes in between. ex: `/`, `/path`, `/path/to/the/app`.
@Deprecated(
'Use uri instead. '
'This feature was deprecated after v3.8.0-3.0.pre.'
)
String get location {
if (_location != null) {
return _location!;
}
return Uri.decodeComponent(
Uri(
path: uri.path.isEmpty ? '/' : uri.path,
queryParameters: uri.queryParametersAll.isEmpty ? null : uri.queryParametersAll,
fragment: uri.fragment.isEmpty ? null : uri.fragment,
).toString(),
);
}
final String? _location;
/// The uri location of the application.
///
/// The host and scheme will not be empty if this object is created from a
/// deep link request. They represents the website that redirect the deep
/// link.
/// ///
/// It is equivalent to the URL in a web application. /// In web platform, the host and scheme are always empty.
final String? location; Uri get uri {
if (_uri != null){
return _uri!;
}
return Uri.parse(_location!);
}
final Uri? _uri;
/// The state of the application in the [location]. /// The state of the application in the [uri].
/// ///
/// The app can have different states even in the same location. For example, /// The app can have different states even in the same location. For example,
/// the text inside a [TextField] or the scroll position in a [ScrollView]. /// the text inside a [TextField] or the scroll position in a [ScrollView].
...@@ -61,11 +100,11 @@ class RouteInformation { ...@@ -61,11 +100,11 @@ class RouteInformation {
/// On the web, this information is stored in the browser history when the /// On the web, this information is stored in the browser history when the
/// [Router] reports this route information back to the web engine /// [Router] reports this route information back to the web engine
/// through the [PlatformRouteInformationProvider]. The information /// through the [PlatformRouteInformationProvider]. The information
/// is then passed back, along with the [location], when the user /// is then passed back, along with the [uri], when the user
/// clicks the back or forward buttons. /// clicks the back or forward buttons.
/// ///
/// This information is also serialized and persisted alongside the /// This information is also serialized and persisted alongside the
/// [location] for state restoration purposes. During state restoration, /// [uri] for state restoration purposes. During state restoration,
/// the information is made available again to the [Router] so it can restore /// the information is made available again to the [Router] so it can restore
/// its configuration to the previous state. /// its configuration to the previous state.
/// ///
...@@ -252,7 +291,7 @@ class RouterConfig<T> { ...@@ -252,7 +291,7 @@ class RouterConfig<T> {
/// ///
/// One can force the [Router] to report new route information as navigation /// One can force the [Router] to report new route information as navigation
/// event to the [routeInformationProvider] (and thus the browser) even if the /// event to the [routeInformationProvider] (and thus the browser) even if the
/// [RouteInformation.location] has not changed by calling the [Router.navigate] /// [RouteInformation.uri] has not changed by calling the [Router.navigate]
/// method with a callback that performs the state change. This causes [Router] /// method with a callback that performs the state change. This causes [Router]
/// to call the [RouteInformationProvider.routerReportsNewRouteInformation] with /// to call the [RouteInformationProvider.routerReportsNewRouteInformation] with
/// [RouteInformationReportingType.navigate], and thus causes /// [RouteInformationReportingType.navigate], and thus causes
...@@ -471,7 +510,7 @@ class Router<T> extends StatefulWidget { ...@@ -471,7 +510,7 @@ class Router<T> extends StatefulWidget {
/// ///
/// The web application relies on the [Router] to report new route information /// The web application relies on the [Router] to report new route information
/// in order to create browser history entry. The [Router] will only report /// in order to create browser history entry. The [Router] will only report
/// them if it detects the [RouteInformation.location] changes. Use this /// them if it detects the [RouteInformation.uri] changes. Use this
/// method if you want the [Router] to report the route information even if /// method if you want the [Router] to report the route information even if
/// the location does not change. This can be useful when you want to /// the location does not change. This can be useful when you want to
/// support the browser backward and forward button without changing the URL. /// support the browser backward and forward button without changing the URL.
...@@ -502,7 +541,7 @@ class Router<T> extends StatefulWidget { ...@@ -502,7 +541,7 @@ class Router<T> extends StatefulWidget {
/// ///
/// The web application relies on the [Router] to report new route information /// The web application relies on the [Router] to report new route information
/// in order to create browser history entry. The [Router] will report them /// in order to create browser history entry. The [Router] will report them
/// automatically if it detects the [RouteInformation.location] changes. /// automatically if it detects the [RouteInformation.uri] changes.
/// ///
/// Creating a new route history entry makes users feel they have visited a /// Creating a new route history entry makes users feel they have visited a
/// new page, and the browser back button brings them back to previous history /// new page, and the browser back button brings them back to previous history
...@@ -1432,10 +1471,10 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid ...@@ -1432,10 +1471,10 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid
final bool replace = final bool replace =
type == RouteInformationReportingType.neglect || type == RouteInformationReportingType.neglect ||
(type == RouteInformationReportingType.none && (type == RouteInformationReportingType.none &&
_valueInEngine.location == routeInformation.location); _valueInEngine.uri == routeInformation.uri);
SystemNavigator.selectMultiEntryHistory(); SystemNavigator.selectMultiEntryHistory();
SystemNavigator.routeInformationUpdated( SystemNavigator.routeInformationUpdated(
location: routeInformation.location!, uri: routeInformation.uri,
state: routeInformation.state, state: routeInformation.state,
replace: replace, replace: replace,
); );
...@@ -1447,7 +1486,7 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid ...@@ -1447,7 +1486,7 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid
RouteInformation get value => _value; RouteInformation get value => _value;
RouteInformation _value; RouteInformation _value;
RouteInformation _valueInEngine = RouteInformation(location: WidgetsBinding.instance.platformDispatcher.defaultRouteName); RouteInformation _valueInEngine = RouteInformation(uri: Uri.parse(WidgetsBinding.instance.platformDispatcher.defaultRouteName));
void _platformReportsNewRouteInformation(RouteInformation routeInformation) { void _platformReportsNewRouteInformation(RouteInformation routeInformation) {
if (_value == routeInformation) { if (_value == routeInformation) {
...@@ -1492,13 +1531,6 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid ...@@ -1492,13 +1531,6 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid
_platformReportsNewRouteInformation(routeInformation); _platformReportsNewRouteInformation(routeInformation);
return true; return true;
} }
@override
Future<bool> didPushRoute(String route) async {
assert(hasListeners);
_platformReportsNewRouteInformation(RouteInformation(location: route));
return true;
}
} }
/// A mixin that wires [RouterDelegate.popRoute] to the [Navigator] it builds. /// A mixin that wires [RouterDelegate.popRoute] to the [Navigator] it builds.
...@@ -1542,11 +1574,15 @@ class _RestorableRouteInformation extends RestorableValue<RouteInformation?> { ...@@ -1542,11 +1574,15 @@ class _RestorableRouteInformation extends RestorableValue<RouteInformation?> {
} }
assert(data is List<Object?> && data.length == 2); assert(data is List<Object?> && data.length == 2);
final List<Object?> castedData = data as List<Object?>; final List<Object?> castedData = data as List<Object?>;
return RouteInformation(location: castedData.first as String?, state: castedData.last); final String? uri = castedData.first as String?;
if (uri == null) {
return null;
}
return RouteInformation(uri: Uri.parse(uri), state: castedData.last);
} }
@override @override
Object? toPrimitives() { Object? toPrimitives() {
return value == null ? null : <Object?>[value!.location, value!.state]; return value == null ? null : <Object?>[value!.uri.toString(), value!.state];
} }
} }
...@@ -148,17 +148,17 @@ void main() { ...@@ -148,17 +148,17 @@ void main() {
testWidgets('CupertinoApp.router works', (WidgetTester tester) async { testWidgets('CupertinoApp.router works', (WidgetTester tester) async {
final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
); );
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
...@@ -180,16 +180,16 @@ void main() { ...@@ -180,16 +180,16 @@ void main() {
testWidgets('CupertinoApp.router route information parser is optional', (WidgetTester tester) async { testWidgets('CupertinoApp.router route information parser is optional', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
); );
delegate.routeInformation = const RouteInformation(location: 'initial'); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial'));
await tester.pumpWidget(CupertinoApp.router( await tester.pumpWidget(CupertinoApp.router(
routerDelegate: delegate, routerDelegate: delegate,
)); ));
...@@ -205,19 +205,19 @@ void main() { ...@@ -205,19 +205,19 @@ void main() {
testWidgets('CupertinoApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async { testWidgets('CupertinoApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
); );
delegate.routeInformation = const RouteInformation(location: 'initial'); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial'));
final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
); );
await tester.pumpWidget(CupertinoApp.router( await tester.pumpWidget(CupertinoApp.router(
...@@ -230,16 +230,16 @@ void main() { ...@@ -230,16 +230,16 @@ void main() {
testWidgets('CupertinoApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async { testWidgets('CupertinoApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
); );
delegate.routeInformation = const RouteInformation(location: 'initial'); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial'));
final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>(routerDelegate: delegate); final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>(routerDelegate: delegate);
await tester.pumpWidget(CupertinoApp.router( await tester.pumpWidget(CupertinoApp.router(
routerDelegate: delegate, routerDelegate: delegate,
...@@ -251,18 +251,18 @@ void main() { ...@@ -251,18 +251,18 @@ void main() {
testWidgets('CupertinoApp.router router config works', (WidgetTester tester) async { testWidgets('CupertinoApp.router router config works', (WidgetTester tester) async {
final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>( final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>(
routeInformationProvider: PlatformRouteInformationProvider( routeInformationProvider: PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
), ),
routeInformationParser: SimpleRouteInformationParser(), routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleNavigatorRouterDelegate( routerDelegate: SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
...@@ -532,7 +532,7 @@ class SimpleNavigatorRouterDelegate extends RouterDelegate<RouteInformation> wit ...@@ -532,7 +532,7 @@ class SimpleNavigatorRouterDelegate extends RouterDelegate<RouteInformation> wit
child: Text('base'), child: Text('base'),
), ),
CupertinoPage<void>( CupertinoPage<void>(
key: ValueKey<String?>(routeInformation.location), key: ValueKey<String?>(routeInformation.uri.toString()),
child: builder(context, routeInformation), child: builder(context, routeInformation),
), ),
], ],
......
...@@ -1085,17 +1085,17 @@ void main() { ...@@ -1085,17 +1085,17 @@ void main() {
testWidgets('MaterialApp.router works', (WidgetTester tester) async { testWidgets('MaterialApp.router works', (WidgetTester tester) async {
final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
); );
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
...@@ -1117,16 +1117,16 @@ void main() { ...@@ -1117,16 +1117,16 @@ void main() {
testWidgets('MaterialApp.router route information parser is optional', (WidgetTester tester) async { testWidgets('MaterialApp.router route information parser is optional', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
); );
delegate.routeInformation = const RouteInformation(location: 'initial'); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial'));
await tester.pumpWidget(MaterialApp.router( await tester.pumpWidget(MaterialApp.router(
routerDelegate: delegate, routerDelegate: delegate,
)); ));
...@@ -1142,19 +1142,19 @@ void main() { ...@@ -1142,19 +1142,19 @@ void main() {
testWidgets('MaterialApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async { testWidgets('MaterialApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
); );
delegate.routeInformation = const RouteInformation(location: 'initial'); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial'));
final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
); );
await tester.pumpWidget(MaterialApp.router( await tester.pumpWidget(MaterialApp.router(
...@@ -1167,16 +1167,16 @@ void main() { ...@@ -1167,16 +1167,16 @@ void main() {
testWidgets('MaterialApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async { testWidgets('MaterialApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
); );
delegate.routeInformation = const RouteInformation(location: 'initial'); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial'));
final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>(routerDelegate: delegate); final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>(routerDelegate: delegate);
await tester.pumpWidget(MaterialApp.router( await tester.pumpWidget(MaterialApp.router(
routerDelegate: delegate, routerDelegate: delegate,
...@@ -1188,18 +1188,18 @@ void main() { ...@@ -1188,18 +1188,18 @@ void main() {
testWidgets('MaterialApp.router router config works', (WidgetTester tester) async { testWidgets('MaterialApp.router router config works', (WidgetTester tester) async {
final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>( final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>(
routeInformationProvider: PlatformRouteInformationProvider( routeInformationProvider: PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
), ),
routeInformationParser: SimpleRouteInformationParser(), routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleNavigatorRouterDelegate( routerDelegate: SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
...@@ -1601,7 +1601,7 @@ class SimpleNavigatorRouterDelegate extends RouterDelegate<RouteInformation> wit ...@@ -1601,7 +1601,7 @@ class SimpleNavigatorRouterDelegate extends RouterDelegate<RouteInformation> wit
child: Text('base'), child: Text('base'),
), ),
MaterialPage<void>( MaterialPage<void>(
key: ValueKey<String>(routeInformation.location!), key: ValueKey<String>(routeInformation.uri.toString()),
child: builder(context, routeInformation), child: builder(context, routeInformation),
), ),
], ],
......
...@@ -45,15 +45,15 @@ void main() { ...@@ -45,15 +45,15 @@ void main() {
]); ]);
await verify(() => SystemNavigator.routeInformationUpdated(location: 'a'), <Object>[ await verify(() => SystemNavigator.routeInformationUpdated(location: 'a'), <Object>[
isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'location': 'a', 'state': null, 'replace': false }), isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'uri': 'a', 'state': null, 'replace': false }),
]); ]);
await verify(() => SystemNavigator.routeInformationUpdated(location: 'a', state: true), <Object>[ await verify(() => SystemNavigator.routeInformationUpdated(location: 'a', state: true), <Object>[
isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'location': 'a', 'state': true, 'replace': false }), isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'uri': 'a', 'state': true, 'replace': false }),
]); ]);
await verify(() => SystemNavigator.routeInformationUpdated(location: 'a', state: true, replace: true), <Object>[ await verify(() => SystemNavigator.routeInformationUpdated(location: 'a', state: true, replace: true), <Object>[
isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'location': 'a', 'state': true, 'replace': true }), isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'uri': 'a', 'state': true, 'replace': true }),
]); ]);
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, null); TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, null);
......
...@@ -275,17 +275,17 @@ void main() { ...@@ -275,17 +275,17 @@ void main() {
testWidgets('WidgetsApp.router works', (WidgetTester tester) async { testWidgets('WidgetsApp.router works', (WidgetTester tester) async {
final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
); );
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
...@@ -308,16 +308,16 @@ void main() { ...@@ -308,16 +308,16 @@ void main() {
testWidgets('WidgetsApp.router route information parser is optional', (WidgetTester tester) async { testWidgets('WidgetsApp.router route information parser is optional', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
); );
delegate.routeInformation = const RouteInformation(location: 'initial'); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial'));
await tester.pumpWidget(WidgetsApp.router( await tester.pumpWidget(WidgetsApp.router(
routerDelegate: delegate, routerDelegate: delegate,
color: const Color(0xFF123456), color: const Color(0xFF123456),
...@@ -334,19 +334,19 @@ void main() { ...@@ -334,19 +334,19 @@ void main() {
testWidgets('WidgetsApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async { testWidgets('WidgetsApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
); );
delegate.routeInformation = const RouteInformation(location: 'initial'); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial'));
final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
); );
await expectLater(() async { await expectLater(() async {
...@@ -361,16 +361,16 @@ void main() { ...@@ -361,16 +361,16 @@ void main() {
testWidgets('WidgetsApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async { testWidgets('WidgetsApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
); );
delegate.routeInformation = const RouteInformation(location: 'initial'); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial'));
final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>(routerDelegate: delegate); final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>(routerDelegate: delegate);
await expectLater(() async { await expectLater(() async {
await tester.pumpWidget(WidgetsApp.router( await tester.pumpWidget(WidgetsApp.router(
...@@ -384,18 +384,18 @@ void main() { ...@@ -384,18 +384,18 @@ void main() {
testWidgets('WidgetsApp.router router config works', (WidgetTester tester) async { testWidgets('WidgetsApp.router router config works', (WidgetTester tester) async {
final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>( final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>(
routeInformationProvider: PlatformRouteInformationProvider( routeInformationProvider: PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
), ),
routeInformationParser: SimpleRouteInformationParser(), routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleNavigatorRouterDelegate( routerDelegate: SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) { onPopPage: (Route<void> route, void result, SimpleNavigatorRouterDelegate delegate) {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
...@@ -418,7 +418,7 @@ void main() { ...@@ -418,7 +418,7 @@ void main() {
testWidgets('WidgetsApp.router has correct default', (WidgetTester tester) async { testWidgets('WidgetsApp.router has correct default', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
onPopPage: (Route<Object?> route, Object? result, SimpleNavigatorRouterDelegate delegate) => true, onPopPage: (Route<Object?> route, Object? result, SimpleNavigatorRouterDelegate delegate) => true,
); );
...@@ -769,7 +769,7 @@ class SimpleNavigatorRouterDelegate extends RouterDelegate<RouteInformation> wit ...@@ -769,7 +769,7 @@ class SimpleNavigatorRouterDelegate extends RouterDelegate<RouteInformation> wit
child: Text('base'), child: Text('base'),
), ),
MaterialPage<void>( MaterialPage<void>(
key: ValueKey<String>(routeInformation.location!), key: ValueKey<String>(routeInformation.uri.toString()),
child: builder(context, routeInformation), child: builder(context, routeInformation),
), ),
], ],
......
...@@ -111,6 +111,38 @@ void main() { ...@@ -111,6 +111,38 @@ void main() {
WidgetsBinding.instance.removeObserver(observer); WidgetsBinding.instance.removeObserver(observer);
}); });
testWidgets('didPushRouteInformation calls didPushRoute correctly when handling url', (WidgetTester tester) async {
final PushRouteObserver observer = PushRouteObserver();
WidgetsBinding.instance.addObserver(observer);
// A url without any path.
Map<String, dynamic> testRouteInformation = const <String, dynamic>{
'location': 'http://hostname',
'state': 'state',
'restorationData': <dynamic, dynamic>{'test': 'config'},
};
ByteData message = const JSONMethodCodec().encodeMethodCall(
MethodCall('pushRouteInformation', testRouteInformation),
);
await ServicesBinding.instance.defaultBinaryMessenger
.handlePlatformMessage('flutter/navigation', message, (_) {});
expect(observer.pushedRoute, '/');
// A complex url.
testRouteInformation = const <String, dynamic>{
'location': 'http://hostname/abc?def=123&def=456#789',
'state': 'state',
'restorationData': <dynamic, dynamic>{'test': 'config'},
};
message = const JSONMethodCodec().encodeMethodCall(
MethodCall('pushRouteInformation', testRouteInformation),
);
await ServicesBinding.instance.defaultBinaryMessenger
.handlePlatformMessage('flutter/navigation', message, (_) {});
expect(observer.pushedRoute, '/abc?def=123&def=456#789');
WidgetsBinding.instance.removeObserver(observer);
});
testWidgets('didPushRouteInformation callback', (WidgetTester tester) async { testWidgets('didPushRouteInformation callback', (WidgetTester tester) async {
final PushRouteInformationObserver observer = PushRouteInformationObserver(); final PushRouteInformationObserver observer = PushRouteInformationObserver();
WidgetsBinding.instance.addObserver(observer); WidgetsBinding.instance.addObserver(observer);
...@@ -123,7 +155,25 @@ void main() { ...@@ -123,7 +155,25 @@ void main() {
const MethodCall('pushRouteInformation', testRouteInformation), const MethodCall('pushRouteInformation', testRouteInformation),
); );
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { }); await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
expect(observer.pushedRouteInformation.location, 'testRouteName'); expect(observer.pushedRouteInformation.uri.toString(), 'testRouteName');
expect(observer.pushedRouteInformation.state, 'state');
WidgetsBinding.instance.removeObserver(observer);
});
testWidgets('didPushRouteInformation callback can handle url', (WidgetTester tester) async {
final PushRouteInformationObserver observer = PushRouteInformationObserver();
WidgetsBinding.instance.addObserver(observer);
const Map<String, dynamic> testRouteInformation = <String, dynamic>{
'location': 'http://hostname/abc?def=123&def=456#789',
'state': 'state',
};
final ByteData message = const JSONMethodCodec().encodeMethodCall(
const MethodCall('pushRouteInformation', testRouteInformation),
);
await ServicesBinding.instance.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
expect(observer.pushedRouteInformation.location, '/abc?def=123&def=456#789');
expect(observer.pushedRouteInformation.uri.toString(), 'http://hostname/abc?def=123&def=456#789');
expect(observer.pushedRouteInformation.state, 'state'); expect(observer.pushedRouteInformation.state, 'state');
WidgetsBinding.instance.removeObserver(observer); WidgetsBinding.instance.removeObserver(observer);
}); });
...@@ -139,8 +189,9 @@ void main() { ...@@ -139,8 +189,9 @@ void main() {
final ByteData message = const JSONMethodCodec().encodeMethodCall( final ByteData message = const JSONMethodCodec().encodeMethodCall(
const MethodCall('pushRouteInformation', testRouteInformation), const MethodCall('pushRouteInformation', testRouteInformation),
); );
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { }); await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
expect(observer.pushedRouteInformation.location, 'testRouteName'); expect(observer.pushedRouteInformation.uri.toString(), 'testRouteName');
expect(observer.pushedRouteInformation.state, null); expect(observer.pushedRouteInformation.state, null);
WidgetsBinding.instance.removeObserver(observer); WidgetsBinding.instance.removeObserver(observer);
}); });
......
...@@ -63,7 +63,7 @@ void main() { ...@@ -63,7 +63,7 @@ void main() {
isMethodCall('selectSingleEntryHistory', arguments: null), isMethodCall('selectSingleEntryHistory', arguments: null),
isMethodCall('routeInformationUpdated', isMethodCall('routeInformationUpdated',
arguments: <String, dynamic>{ arguments: <String, dynamic>{
'location': '/', 'uri': '/',
'state': null, 'state': null,
'replace': false, 'replace': false,
}, },
...@@ -81,7 +81,7 @@ void main() { ...@@ -81,7 +81,7 @@ void main() {
isMethodCall( isMethodCall(
'routeInformationUpdated', 'routeInformationUpdated',
arguments: <String, dynamic>{ arguments: <String, dynamic>{
'location': '/A', 'uri': '/A',
'state': null, 'state': null,
'replace': false, 'replace': false,
}, },
...@@ -99,7 +99,7 @@ void main() { ...@@ -99,7 +99,7 @@ void main() {
isMethodCall( isMethodCall(
'routeInformationUpdated', 'routeInformationUpdated',
arguments: <String, dynamic>{ arguments: <String, dynamic>{
'location': '/', 'uri': '/',
'state': null, 'state': null,
'replace': false, 'replace': false,
}, },
...@@ -173,7 +173,7 @@ void main() { ...@@ -173,7 +173,7 @@ void main() {
isMethodCall('selectSingleEntryHistory', arguments: null), isMethodCall('selectSingleEntryHistory', arguments: null),
isMethodCall('routeInformationUpdated', isMethodCall('routeInformationUpdated',
arguments: <String, dynamic>{ arguments: <String, dynamic>{
'location': '/', 'uri': '/',
'state': null, 'state': null,
'replace': false, 'replace': false,
}, },
...@@ -191,7 +191,7 @@ void main() { ...@@ -191,7 +191,7 @@ void main() {
isMethodCall( isMethodCall(
'routeInformationUpdated', 'routeInformationUpdated',
arguments: <String, dynamic>{ arguments: <String, dynamic>{
'location': '/A', 'uri': '/A',
'state': null, 'state': null,
'replace': false, 'replace': false,
}, },
...@@ -209,7 +209,7 @@ void main() { ...@@ -209,7 +209,7 @@ void main() {
isMethodCall( isMethodCall(
'routeInformationUpdated', 'routeInformationUpdated',
arguments: <String, dynamic>{ arguments: <String, dynamic>{
'location': '/B', 'uri': '/B',
'state': null, 'state': null,
'replace': false, 'replace': false,
}, },
...@@ -246,7 +246,7 @@ void main() { ...@@ -246,7 +246,7 @@ void main() {
isMethodCall('selectSingleEntryHistory', arguments: null), isMethodCall('selectSingleEntryHistory', arguments: null),
isMethodCall('routeInformationUpdated', isMethodCall('routeInformationUpdated',
arguments: <String, dynamic>{ arguments: <String, dynamic>{
'location': '/home', 'uri': '/home',
'state': null, 'state': null,
'replace': false, 'replace': false,
}, },
...@@ -269,14 +269,14 @@ void main() { ...@@ -269,14 +269,14 @@ void main() {
}); });
final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
); );
final SimpleRouterDelegate delegate = SimpleRouterDelegate( final SimpleRouterDelegate delegate = SimpleRouterDelegate(
reportConfiguration: true, reportConfiguration: true,
builder: (BuildContext context, RouteInformation information) { builder: (BuildContext context, RouteInformation information) {
return Text(information.location!); return Text(information.uri.toString());
}, },
); );
...@@ -289,7 +289,7 @@ void main() { ...@@ -289,7 +289,7 @@ void main() {
expect(log, <Object>[ expect(log, <Object>[
isMethodCall('selectMultiEntryHistory', arguments: null), isMethodCall('selectMultiEntryHistory', arguments: null),
isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{
'location': 'initial', 'uri': 'initial',
'state': null, 'state': null,
'replace': false, 'replace': false,
}), }),
...@@ -298,8 +298,8 @@ void main() { ...@@ -298,8 +298,8 @@ void main() {
// Triggers a router rebuild and verify the route information is reported // Triggers a router rebuild and verify the route information is reported
// to the web engine. // to the web engine.
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'update', uri: Uri.parse('update'),
state: 'state', state: 'state',
); );
await tester.pump(); await tester.pump();
...@@ -308,7 +308,7 @@ void main() { ...@@ -308,7 +308,7 @@ void main() {
expect(log, <Object>[ expect(log, <Object>[
isMethodCall('selectMultiEntryHistory', arguments: null), isMethodCall('selectMultiEntryHistory', arguments: null),
isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{
'location': 'update', 'uri': 'update',
'state': 'state', 'state': 'state',
'replace': false, 'replace': false,
}), }),
......
...@@ -51,7 +51,7 @@ void main() { ...@@ -51,7 +51,7 @@ void main() {
expect(delegate().newRoutePaths, <String>['/home']); expect(delegate().newRoutePaths, <String>['/home']);
expect(delegate().restoredRoutePaths, isEmpty); expect(delegate().restoredRoutePaths, isEmpty);
provider().value = const RouteInformation(location: '/foo'); provider().value = RouteInformation(uri: Uri(path: '/foo'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('Current config: /foo'), findsOneWidget); expect(find.text('Current config: /foo'), findsOneWidget);
expect(delegate().newRoutePaths, <String>['/home', '/foo']); expect(delegate().newRoutePaths, <String>['/home', '/foo']);
...@@ -64,7 +64,7 @@ void main() { ...@@ -64,7 +64,7 @@ void main() {
final TestRestorationData restorationData = await tester.getRestorationData(); final TestRestorationData restorationData = await tester.getRestorationData();
provider().value = const RouteInformation(location: '/bar'); provider().value = RouteInformation(uri: Uri.parse('/bar'));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('Current config: /bar'), findsOneWidget); expect(find.text('Current config: /bar'), findsOneWidget);
expect(delegate().newRoutePaths, <String>['/bar']); expect(delegate().newRoutePaths, <String>['/bar']);
...@@ -80,12 +80,12 @@ void main() { ...@@ -80,12 +80,12 @@ void main() {
class _TestRouteInformationParser extends RouteInformationParser<String> { class _TestRouteInformationParser extends RouteInformationParser<String> {
@override @override
Future<String> parseRouteInformation(RouteInformation routeInformation) { Future<String> parseRouteInformation(RouteInformation routeInformation) {
return SynchronousFuture<String>(routeInformation.location!); return SynchronousFuture<String>(routeInformation.uri.toString());
} }
@override @override
RouteInformation? restoreRouteInformation(String configuration) { RouteInformation? restoreRouteInformation(String configuration) {
return RouteInformation(location: configuration); return RouteInformation(uri: Uri.parse(configuration));
} }
} }
...@@ -130,7 +130,7 @@ class _TestRouterDelegate extends RouterDelegate<String> with ChangeNotifier { ...@@ -130,7 +130,7 @@ class _TestRouterDelegate extends RouterDelegate<String> with ChangeNotifier {
class _TestRouteInformationProvider extends RouteInformationProvider with ChangeNotifier { class _TestRouteInformationProvider extends RouteInformationProvider with ChangeNotifier {
@override @override
RouteInformation get value => _value; RouteInformation get value => _value;
RouteInformation _value = const RouteInformation(location: '/home'); RouteInformation _value = RouteInformation(uri: Uri.parse('/home'));
set value(RouteInformation value) { set value(RouteInformation value) {
if (value == _value) { if (value == _value) {
return; return;
......
...@@ -12,8 +12,8 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -12,8 +12,8 @@ import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
testWidgets('Simple router basic functionality - synchronized', (WidgetTester tester) async { testWidgets('Simple router basic functionality - synchronized', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
await tester.pumpWidget(buildBoilerPlate( await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>( Router<RouteInformation>(
...@@ -21,15 +21,15 @@ void main() { ...@@ -21,15 +21,15 @@ void main() {
routeInformationParser: SimpleRouteInformationParser(), routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleRouterDelegate( routerDelegate: SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) { builder: (BuildContext context, RouteInformation? information) {
return Text(information!.location!); return Text(Uri.decodeComponent(information!.uri.toString()));
}, },
), ),
), ),
)); ));
expect(find.text('initial'), findsOneWidget); expect(find.text('initial'), findsOneWidget);
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'update', uri: Uri.parse('update'),
); );
await tester.pump(); await tester.pump();
expect(find.text('initial'), findsNothing); expect(find.text('initial'), findsNothing);
...@@ -38,8 +38,8 @@ void main() { ...@@ -38,8 +38,8 @@ void main() {
testWidgets('Simple router basic functionality - asynchronized', (WidgetTester tester) async { testWidgets('Simple router basic functionality - asynchronized', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final SimpleAsyncRouteInformationParser parser = SimpleAsyncRouteInformationParser(); final SimpleAsyncRouteInformationParser parser = SimpleAsyncRouteInformationParser();
final SimpleAsyncRouterDelegate delegate = SimpleAsyncRouterDelegate( final SimpleAsyncRouterDelegate delegate = SimpleAsyncRouterDelegate(
...@@ -47,7 +47,7 @@ void main() { ...@@ -47,7 +47,7 @@ void main() {
if (information == null) { if (information == null) {
return const Text('waiting'); return const Text('waiting');
} }
return Text(information.location!); return Text(information.uri.toString());
}, },
); );
await tester.runAsync(() async { await tester.runAsync(() async {
...@@ -66,8 +66,8 @@ void main() { ...@@ -66,8 +66,8 @@ void main() {
await tester.pump(); await tester.pump();
expect(find.text('initial'), findsOneWidget); expect(find.text('initial'), findsOneWidget);
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'update', uri: Uri.parse('update'),
); );
await tester.pump(); await tester.pump();
// Future has not yet completed. // Future has not yet completed.
...@@ -82,8 +82,8 @@ void main() { ...@@ -82,8 +82,8 @@ void main() {
testWidgets('Interrupts route parsing should not crash', (WidgetTester tester) async { testWidgets('Interrupts route parsing should not crash', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final CompleterRouteInformationParser parser = CompleterRouteInformationParser(); final CompleterRouteInformationParser parser = CompleterRouteInformationParser();
final SimpleAsyncRouterDelegate delegate = SimpleAsyncRouterDelegate( final SimpleAsyncRouterDelegate delegate = SimpleAsyncRouterDelegate(
...@@ -91,7 +91,7 @@ void main() { ...@@ -91,7 +91,7 @@ void main() {
if (information == null) { if (information == null) {
return const Text('waiting'); return const Text('waiting');
} }
return Text(information.location!); return Text(information.uri.toString());
}, },
); );
await tester.runAsync(() async { await tester.runAsync(() async {
...@@ -108,8 +108,8 @@ void main() { ...@@ -108,8 +108,8 @@ void main() {
final Completer<void> firstTransactionCompleter = parser.completer; final Completer<void> firstTransactionCompleter = parser.completer;
// Start a new parsing transaction before the previous one complete. // Start a new parsing transaction before the previous one complete.
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'update', uri: Uri.parse('update'),
); );
await tester.pump(); await tester.pump();
expect(find.text('waiting'), findsOneWidget); expect(find.text('waiting'), findsOneWidget);
...@@ -148,8 +148,8 @@ void main() { ...@@ -148,8 +148,8 @@ void main() {
testWidgets('Simple router can handle pop route', (WidgetTester tester) async { testWidgets('Simple router can handle pop route', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher dispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher dispatcher = RootBackButtonDispatcher();
...@@ -159,11 +159,11 @@ void main() { ...@@ -159,11 +159,11 @@ void main() {
routeInformationParser: SimpleRouteInformationParser(), routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleRouterDelegate( routerDelegate: SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) { builder: (BuildContext context, RouteInformation? information) {
return Text(information!.location!); return Text(Uri.decodeComponent(information!.uri.toString()));
}, },
onPopRoute: () { onPopRoute: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -187,8 +187,8 @@ void main() { ...@@ -187,8 +187,8 @@ void main() {
testWidgets('Router throw when passing routeInformationProvider without routeInformationParser', (WidgetTester tester) async { testWidgets('Router throw when passing routeInformationProvider without routeInformationParser', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
expect( expect(
() { () {
...@@ -196,7 +196,7 @@ void main() { ...@@ -196,7 +196,7 @@ void main() {
routeInformationProvider: provider, routeInformationProvider: provider,
routerDelegate: SimpleRouterDelegate( routerDelegate: SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) { builder: (BuildContext context, RouteInformation? information) {
return Text(information!.location!); return Text(Uri.decodeComponent(information!.uri.toString()));
}, },
), ),
); );
...@@ -211,17 +211,17 @@ void main() { ...@@ -211,17 +211,17 @@ void main() {
testWidgets('PopNavigatorRouterDelegateMixin works', (WidgetTester tester) async { testWidgets('PopNavigatorRouterDelegateMixin works', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher dispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher dispatcher = RootBackButtonDispatcher();
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
builder: (BuildContext context, RouteInformation? information) { builder: (BuildContext context, RouteInformation? information) {
return Text(information!.location!); return Text(Uri.decodeComponent(information!.uri.toString()));
}, },
onPopPage: (Route<void> route, void result) { onPopPage: (Route<void> route, void result) {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return route.didPop(result); return route.didPop(result);
}, },
...@@ -264,8 +264,8 @@ void main() { ...@@ -264,8 +264,8 @@ void main() {
testWidgets('Nested routers back button dispatcher works', (WidgetTester tester) async { testWidgets('Nested routers back button dispatcher works', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
await tester.pumpWidget(buildBoilerPlate( await tester.pumpWidget(buildBoilerPlate(
...@@ -282,11 +282,11 @@ void main() { ...@@ -282,11 +282,11 @@ void main() {
backButtonDispatcher: innerDispatcher, backButtonDispatcher: innerDispatcher,
routerDelegate: SimpleRouterDelegate( routerDelegate: SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? innerInformation) { builder: (BuildContext context, RouteInformation? innerInformation) {
return Text(information!.location!); return Text(Uri.decodeComponent(information!.uri.toString()));
}, },
onPopRoute: () { onPopRoute: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped inner', uri: Uri.parse('popped inner'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -294,8 +294,8 @@ void main() { ...@@ -294,8 +294,8 @@ void main() {
); );
}, },
onPopRoute: () { onPopRoute: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped outer', uri: Uri.parse('popped outer'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -314,8 +314,8 @@ void main() { ...@@ -314,8 +314,8 @@ void main() {
testWidgets('Nested router back button dispatcher works for multiple children', (WidgetTester tester) async { testWidgets('Nested router back button dispatcher works for multiple children', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
final BackButtonDispatcher innerDispatcher1 = ChildBackButtonDispatcher(outerDispatcher); final BackButtonDispatcher innerDispatcher1 = ChildBackButtonDispatcher(outerDispatcher);
...@@ -330,7 +330,7 @@ void main() { ...@@ -330,7 +330,7 @@ void main() {
// Creates the sub-router. // Creates the sub-router.
return Column( return Column(
children: <Widget>[ children: <Widget>[
Text(information!.location!), Text(Uri.decodeComponent(information!.uri.toString())),
Router<RouteInformation>( Router<RouteInformation>(
backButtonDispatcher: innerDispatcher1, backButtonDispatcher: innerDispatcher1,
routerDelegate: SimpleRouterDelegate( routerDelegate: SimpleRouterDelegate(
...@@ -338,8 +338,8 @@ void main() { ...@@ -338,8 +338,8 @@ void main() {
return Container(); return Container();
}, },
onPopRoute: () { onPopRoute: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped inner1', uri: Uri.parse('popped inner1'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -352,8 +352,8 @@ void main() { ...@@ -352,8 +352,8 @@ void main() {
return Container(); return Container();
}, },
onPopRoute: () { onPopRoute: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped inner2', uri: Uri.parse('popped inner2'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -363,8 +363,8 @@ void main() { ...@@ -363,8 +363,8 @@ void main() {
); );
}, },
onPopRoute: () { onPopRoute: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped outer', uri: Uri.parse('popped outer'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -522,19 +522,19 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -522,19 +522,19 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
final SimpleRouterDelegate delegate = SimpleRouterDelegate( final SimpleRouterDelegate delegate = SimpleRouterDelegate(
reportConfiguration: true, reportConfiguration: true,
builder: (BuildContext context, RouteInformation? information) { builder: (BuildContext context, RouteInformation? information) {
return Text(information!.location!); return Text(Uri.decodeComponent(information!.uri.toString()));
}, },
); );
delegate.onPopRoute = () { delegate.onPopRoute = () {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}; };
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
await tester.pumpWidget(buildBoilerPlate( await tester.pumpWidget(buildBoilerPlate(
...@@ -546,29 +546,29 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -546,29 +546,29 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
), ),
)); ));
expect(find.text('initial'), findsOneWidget); expect(find.text('initial'), findsOneWidget);
expect(reportedRouteInformation!.location, 'initial'); expect(reportedRouteInformation!.uri.toString(), 'initial');
expect(reportedType, RouteInformationReportingType.none); expect(reportedType, RouteInformationReportingType.none);
reportedRouteInformation = null; reportedRouteInformation = null;
reportedType = null; reportedType = null;
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'update', uri: Uri.parse('update'),
); );
await tester.pump(); await tester.pump();
expect(find.text('initial'), findsNothing); expect(find.text('initial'), findsNothing);
expect(find.text('update'), findsOneWidget); expect(find.text('update'), findsOneWidget);
expect(reportedRouteInformation!.location, 'update'); expect(reportedRouteInformation!.uri.toString(), 'update');
expect(reportedType, RouteInformationReportingType.none); expect(reportedType, RouteInformationReportingType.none);
// The router should report as non navigation event if only state changes. // The router should report as non navigation event if only state changes.
reportedRouteInformation = null; reportedRouteInformation = null;
reportedType = null; reportedType = null;
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'update', uri: Uri.parse('update'),
state: 'another state', state: 'another state',
); );
await tester.pump(); await tester.pump();
expect(find.text('update'), findsOneWidget); expect(find.text('update'), findsOneWidget);
expect(reportedRouteInformation!.location, 'update'); expect(reportedRouteInformation!.uri.toString(), 'update');
expect(reportedRouteInformation!.state, 'another state'); expect(reportedRouteInformation!.state, 'another state');
expect(reportedType, RouteInformationReportingType.none); expect(reportedType, RouteInformationReportingType.none);
...@@ -579,7 +579,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -579,7 +579,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(result, isTrue); expect(result, isTrue);
await tester.pump(); await tester.pump();
expect(find.text('popped'), findsOneWidget); expect(find.text('popped'), findsOneWidget);
expect(reportedRouteInformation!.location, 'popped'); expect(reportedRouteInformation!.uri.toString(), 'popped');
expect(reportedType, RouteInformationReportingType.none); expect(reportedType, RouteInformationReportingType.none);
}); });
...@@ -597,13 +597,13 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -597,13 +597,13 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
reportedType = type; reportedType = type;
}, },
); );
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final SimpleRouterDelegate delegate = SimpleRouterDelegate(reportConfiguration: true); final SimpleRouterDelegate delegate = SimpleRouterDelegate(reportConfiguration: true);
delegate.builder = (BuildContext context, RouteInformation? information) { delegate.builder = (BuildContext context, RouteInformation? information) {
return ElevatedButton( return ElevatedButton(
child: Text(information!.location!), child: Text(Uri.decodeComponent(information!.uri.toString())),
onPressed: () { onPressed: () {
if (isNavigating) { if (isNavigating) {
Router.navigate(context, () { Router.navigate(context, () {
...@@ -632,20 +632,20 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -632,20 +632,20 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
), ),
)); ));
expect(find.text('initial'), findsOneWidget); expect(find.text('initial'), findsOneWidget);
expect(reportedRouteInformation!.location, 'initial'); expect(reportedRouteInformation!.uri.toString(), 'initial');
expect(reportedType, RouteInformationReportingType.none); expect(reportedType, RouteInformationReportingType.none);
reportedType = null; reportedType = null;
reportedRouteInformation = null; reportedRouteInformation = null;
nextRouteInformation = const RouteInformation( nextRouteInformation = RouteInformation(
location: 'update', uri: Uri.parse('update'),
); );
await tester.tap(find.byType(ElevatedButton)); await tester.tap(find.byType(ElevatedButton));
await tester.pump(); await tester.pump();
expect(find.text('initial'), findsNothing); expect(find.text('initial'), findsNothing);
expect(find.text('update'), findsOneWidget); expect(find.text('update'), findsOneWidget);
expect(reportedType, RouteInformationReportingType.neglect); expect(reportedType, RouteInformationReportingType.neglect);
expect(reportedRouteInformation!.location, 'update'); expect(reportedRouteInformation!.uri.toString(), 'update');
reportedType = null; reportedType = null;
reportedRouteInformation = null; reportedRouteInformation = null;
...@@ -656,7 +656,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -656,7 +656,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
await tester.tap(find.byType(ElevatedButton)); await tester.tap(find.byType(ElevatedButton));
await tester.pump(); await tester.pump();
expect(reportedType, RouteInformationReportingType.navigate); expect(reportedType, RouteInformationReportingType.navigate);
expect(reportedRouteInformation!.location, 'update'); expect(reportedRouteInformation!.uri.toString(), 'update');
reportedType = null; reportedType = null;
reportedRouteInformation = null; reportedRouteInformation = null;
}); });
...@@ -673,13 +673,13 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -673,13 +673,13 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
reportingType = type; reportingType = type;
}, },
); );
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final SimpleRouterDelegate delegate = SimpleRouterDelegate(reportConfiguration: true); final SimpleRouterDelegate delegate = SimpleRouterDelegate(reportConfiguration: true);
delegate.builder = (BuildContext context, RouteInformation? information) { delegate.builder = (BuildContext context, RouteInformation? information) {
return ElevatedButton( return ElevatedButton(
child: Text(information!.location!), child: Text(Uri.decodeComponent(information!.uri.toString())),
onPressed: () { onPressed: () {
Router.neglect(context, () { Router.neglect(context, () {
if (delegate.routeInformation != nextRouteInformation) { if (delegate.routeInformation != nextRouteInformation) {
...@@ -700,19 +700,19 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -700,19 +700,19 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
), ),
)); ));
expect(find.text('initial'), findsOneWidget); expect(find.text('initial'), findsOneWidget);
expect(updatedRouteInformation!.location, 'initial'); expect(updatedRouteInformation!.uri.toString(), 'initial');
expect(reportingType, RouteInformationReportingType.none); expect(reportingType, RouteInformationReportingType.none);
updatedRouteInformation = null; updatedRouteInformation = null;
reportingType = null; reportingType = null;
nextRouteInformation = const RouteInformation( nextRouteInformation = RouteInformation(
location: 'update', uri: Uri.parse('update'),
); );
await tester.tap(find.byType(ElevatedButton)); await tester.tap(find.byType(ElevatedButton));
await tester.pump(); await tester.pump();
expect(find.text('initial'), findsNothing); expect(find.text('initial'), findsNothing);
expect(find.text('update'), findsOneWidget); expect(find.text('update'), findsOneWidget);
expect(updatedRouteInformation!.location, 'update'); expect(updatedRouteInformation!.uri.toString(), 'update');
expect(reportingType, RouteInformationReportingType.neglect); expect(reportingType, RouteInformationReportingType.neglect);
}); });
...@@ -729,14 +729,14 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -729,14 +729,14 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
reportingType = type; reportingType = type;
}, },
); );
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
state: 'state1', state: 'state1',
); );
final SimpleRouterDelegate delegate = SimpleRouterDelegate(reportConfiguration: true); final SimpleRouterDelegate delegate = SimpleRouterDelegate(reportConfiguration: true);
delegate.builder = (BuildContext context, RouteInformation? information) { delegate.builder = (BuildContext context, RouteInformation? information) {
return ElevatedButton( return ElevatedButton(
child: Text(information!.location!), child: Text(Uri.decodeComponent(information!.uri.toString())),
onPressed: () { onPressed: () {
delegate.routeInformation = nextRouteInformation; delegate.routeInformation = nextRouteInformation;
}, },
...@@ -753,33 +753,33 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -753,33 +753,33 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
), ),
)); ));
expect(find.text('initial'), findsOneWidget); expect(find.text('initial'), findsOneWidget);
expect(updatedRouteInformation!.location, 'initial'); expect(updatedRouteInformation!.uri.toString(), 'initial');
expect(reportingType, RouteInformationReportingType.none); expect(reportingType, RouteInformationReportingType.none);
updatedRouteInformation = null; updatedRouteInformation = null;
reportingType = null; reportingType = null;
nextRouteInformation = const RouteInformation( nextRouteInformation = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
state: 'state2', state: 'state2',
); );
await tester.tap(find.byType(ElevatedButton)); await tester.tap(find.byType(ElevatedButton));
await tester.pump(); await tester.pump();
expect(updatedRouteInformation!.location, 'initial'); expect(updatedRouteInformation!.uri.toString(), 'initial');
expect(updatedRouteInformation!.state, 'state2'); expect(updatedRouteInformation!.state, 'state2');
expect(reportingType, RouteInformationReportingType.none); expect(reportingType, RouteInformationReportingType.none);
}); });
testWidgets('PlatformRouteInformationProvider works', (WidgetTester tester) async { testWidgets('PlatformRouteInformationProvider works', (WidgetTester tester) async {
final RouteInformationProvider provider = PlatformRouteInformationProvider( final RouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
); );
final SimpleRouterDelegate delegate = SimpleRouterDelegate( final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) { builder: (BuildContext context, RouteInformation? information) {
final List<Widget> children = <Widget>[]; final List<Widget> children = <Widget>[];
if (information!.location != null) { if (information!.uri.toString().isNotEmpty) {
children.add(Text(information.location!)); children.add(Text(information.uri.toString()));
} }
if (information.state != null) { if (information.state != null) {
children.add(Text(information.state.toString())); children.add(Text(information.state.toString()));
...@@ -832,57 +832,57 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -832,57 +832,57 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
} }
); );
final RouteInformationProvider provider = PlatformRouteInformationProvider( final RouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
); );
log.clear(); log.clear();
provider.routerReportsNewRouteInformation(const RouteInformation(location: 'a', state: true)); provider.routerReportsNewRouteInformation(RouteInformation(uri: Uri.parse('a'), state: true));
// Implicit reporting pushes new history entry if the location changes. // Implicit reporting pushes new history entry if the location changes.
expect(log, <Object>[ expect(log, <Object>[
isMethodCall('selectMultiEntryHistory', arguments: null), isMethodCall('selectMultiEntryHistory', arguments: null),
isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'location': 'a', 'state': true, 'replace': false }), isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'uri': 'a', 'state': true, 'replace': false }),
]); ]);
log.clear(); log.clear();
provider.routerReportsNewRouteInformation(const RouteInformation(location: 'a', state: false)); provider.routerReportsNewRouteInformation(RouteInformation(uri: Uri.parse('a'), state: false));
// Since the location is the same, the provider sends replaces message. // Since the location is the same, the provider sends replaces message.
expect(log, <Object>[ expect(log, <Object>[
isMethodCall('selectMultiEntryHistory', arguments: null), isMethodCall('selectMultiEntryHistory', arguments: null),
isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'location': 'a', 'state': false, 'replace': true }), isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'uri': 'a', 'state': false, 'replace': true }),
]); ]);
log.clear(); log.clear();
provider.routerReportsNewRouteInformation(const RouteInformation(location: 'b', state: false), type: RouteInformationReportingType.neglect); provider.routerReportsNewRouteInformation(RouteInformation(uri: Uri.parse('b'), state: false), type: RouteInformationReportingType.neglect);
expect(log, <Object>[ expect(log, <Object>[
isMethodCall('selectMultiEntryHistory', arguments: null), isMethodCall('selectMultiEntryHistory', arguments: null),
isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'location': 'b', 'state': false, 'replace': true }), isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'uri': 'b', 'state': false, 'replace': true }),
]); ]);
log.clear(); log.clear();
provider.routerReportsNewRouteInformation(const RouteInformation(location: 'b', state: false), type: RouteInformationReportingType.navigate); provider.routerReportsNewRouteInformation(RouteInformation(uri: Uri.parse('b'), state: false), type: RouteInformationReportingType.navigate);
expect(log, <Object>[ expect(log, <Object>[
isMethodCall('selectMultiEntryHistory', arguments: null), isMethodCall('selectMultiEntryHistory', arguments: null),
isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'location': 'b', 'state': false, 'replace': false }), isMethodCall('routeInformationUpdated', arguments: <String, dynamic>{ 'uri': 'b', 'state': false, 'replace': false }),
]); ]);
}); });
testWidgets('RootBackButtonDispatcher works', (WidgetTester tester) async { testWidgets('RootBackButtonDispatcher works', (WidgetTester tester) async {
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
final RouteInformationProvider provider = PlatformRouteInformationProvider( final RouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation( initialRouteInformation: RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
), ),
); );
final SimpleRouterDelegate delegate = SimpleRouterDelegate( final SimpleRouterDelegate delegate = SimpleRouterDelegate(
reportConfiguration: true, reportConfiguration: true,
builder: (BuildContext context, RouteInformation? information) { builder: (BuildContext context, RouteInformation? information) {
return Text(information!.location!); return Text(Uri.decodeComponent(information!.uri.toString()));
}, },
); );
delegate.onPopRoute = () { delegate.onPopRoute = () {
delegate.routeInformation = const RouteInformation( delegate.routeInformation = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}; };
...@@ -904,8 +904,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -904,8 +904,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
testWidgets('BackButtonListener takes priority over root back dispatcher', (WidgetTester tester) async { testWidgets('BackButtonListener takes priority over root back dispatcher', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
await tester.pumpWidget(buildBoilerPlate( await tester.pumpWidget(buildBoilerPlate(
...@@ -918,12 +918,12 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -918,12 +918,12 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
// Creates the sub-router. // Creates the sub-router.
return Column( return Column(
children: <Widget>[ children: <Widget>[
Text(information!.location!), Text(Uri.decodeComponent(information!.uri.toString())),
BackButtonListener( BackButtonListener(
child: Container(), child: Container(),
onBackButtonPressed: () { onBackButtonPressed: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped inner1', uri: Uri.parse('popped inner1'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -932,8 +932,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -932,8 +932,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
); );
}, },
onPopRoute: () { onPopRoute: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped outer', uri: Uri.parse('popped outer'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -951,8 +951,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -951,8 +951,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
testWidgets('BackButtonListener updates callback if it has been changed', (WidgetTester tester) async { testWidgets('BackButtonListener updates callback if it has been changed', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
final SimpleRouterDelegate routerDelegate = SimpleRouterDelegate() final SimpleRouterDelegate routerDelegate = SimpleRouterDelegate()
...@@ -960,12 +960,12 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -960,12 +960,12 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
// Creates the sub-router. // Creates the sub-router.
return Column( return Column(
children: <Widget>[ children: <Widget>[
Text(information!.location!), Text(Uri.decodeComponent(information!.uri.toString())),
BackButtonListener( BackButtonListener(
child: Container(), child: Container(),
onBackButtonPressed: () { onBackButtonPressed: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'first callback', uri: Uri.parse('first callback'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -974,8 +974,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -974,8 +974,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
); );
} }
..onPopRoute = () { ..onPopRoute = () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped outer', uri: Uri.parse('popped outer'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}; };
...@@ -994,12 +994,12 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -994,12 +994,12 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
// Creates the sub-router. // Creates the sub-router.
return Column( return Column(
children: <Widget>[ children: <Widget>[
Text(information!.location!), Text(Uri.decodeComponent(information!.uri.toString())),
BackButtonListener( BackButtonListener(
child: Container(), child: Container(),
onBackButtonPressed: () { onBackButtonPressed: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'second callback', uri: Uri.parse('second callback'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -1008,8 +1008,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1008,8 +1008,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
); );
} }
..onPopRoute = () { ..onPopRoute = () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped outer', uri: Uri.parse('popped outer'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}; };
...@@ -1030,8 +1030,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1030,8 +1030,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
testWidgets('BackButtonListener clears callback if it is disposed', (WidgetTester tester) async { testWidgets('BackButtonListener clears callback if it is disposed', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
final SimpleRouterDelegate routerDelegate = SimpleRouterDelegate() final SimpleRouterDelegate routerDelegate = SimpleRouterDelegate()
...@@ -1039,12 +1039,12 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1039,12 +1039,12 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
// Creates the sub-router. // Creates the sub-router.
return Column( return Column(
children: <Widget>[ children: <Widget>[
Text(information!.location!), Text(Uri.decodeComponent(information!.uri.toString())),
BackButtonListener( BackButtonListener(
child: Container(), child: Container(),
onBackButtonPressed: () { onBackButtonPressed: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'first callback', uri: Uri.parse('first callback'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -1053,8 +1053,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1053,8 +1053,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
); );
} }
..onPopRoute = () { ..onPopRoute = () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped outer', uri: Uri.parse('popped outer'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}; };
...@@ -1073,13 +1073,13 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1073,13 +1073,13 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
// Creates the sub-router. // Creates the sub-router.
return Column( return Column(
children: <Widget>[ children: <Widget>[
Text(information!.location!), Text(Uri.decodeComponent(information!.uri.toString())),
], ],
); );
} }
..onPopRoute = () { ..onPopRoute = () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped outer', uri: Uri.parse('popped outer'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}; };
...@@ -1100,8 +1100,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1100,8 +1100,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
testWidgets('Nested backButtonListener should take priority', (WidgetTester tester) async { testWidgets('Nested backButtonListener should take priority', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
await tester.pumpWidget(buildBoilerPlate( await tester.pumpWidget(buildBoilerPlate(
...@@ -1114,20 +1114,20 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1114,20 +1114,20 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
// Creates the sub-router. // Creates the sub-router.
return Column( return Column(
children: <Widget>[ children: <Widget>[
Text(information!.location!), Text(Uri.decodeComponent(information!.uri.toString())),
BackButtonListener( BackButtonListener(
child: BackButtonListener( child: BackButtonListener(
child: Container(), child: Container(),
onBackButtonPressed: () { onBackButtonPressed: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped inner2', uri: Uri.parse('popped inner2'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
), ),
onBackButtonPressed: () { onBackButtonPressed: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped inner1', uri: Uri.parse('popped inner1'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -1136,8 +1136,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1136,8 +1136,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
); );
}, },
onPopRoute: () { onPopRoute: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped outer', uri: Uri.parse('popped outer'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -1155,8 +1155,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1155,8 +1155,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
testWidgets('Nested backButtonListener that returns false should call next on the line', (WidgetTester tester) async { testWidgets('Nested backButtonListener that returns false should call next on the line', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
await tester.pumpWidget(buildBoilerPlate( await tester.pumpWidget(buildBoilerPlate(
...@@ -1169,20 +1169,20 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1169,20 +1169,20 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
// Creates the sub-router. // Creates the sub-router.
return Column( return Column(
children: <Widget>[ children: <Widget>[
Text(information!.location!), Text(Uri.decodeComponent(information!.uri.toString())),
BackButtonListener( BackButtonListener(
child: BackButtonListener( child: BackButtonListener(
child: Container(), child: Container(),
onBackButtonPressed: () { onBackButtonPressed: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped inner2', uri: Uri.parse('popped inner2'),
); );
return SynchronousFuture<bool>(false); return SynchronousFuture<bool>(false);
}, },
), ),
onBackButtonPressed: () { onBackButtonPressed: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped inner1', uri: Uri.parse('popped inner1'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -1191,8 +1191,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1191,8 +1191,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
); );
}, },
onPopRoute: () { onPopRoute: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped outer', uri: Uri.parse('popped outer'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -1210,8 +1210,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1210,8 +1210,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
testWidgets('`didUpdateWidget` test', (WidgetTester tester) async { testWidgets('`didUpdateWidget` test', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
late StateSetter setState; late StateSetter setState;
...@@ -1221,7 +1221,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1221,7 +1221,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
// Creates the sub-router. // Creates the sub-router.
return Column( return Column(
children: <Widget>[ children: <Widget>[
Text(information!.location!), Text(Uri.decodeComponent(information!.uri.toString())),
StatefulBuilder( StatefulBuilder(
builder: (BuildContext context, StateSetter setter) { builder: (BuildContext context, StateSetter setter) {
setState = setter; setState = setter;
...@@ -1229,7 +1229,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1229,7 +1229,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
child: Container(), child: Container(),
onBackButtonPressed: () { onBackButtonPressed: () {
provider.value = RouteInformation( provider.value = RouteInformation(
location: location, uri: Uri.parse(location),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -1240,8 +1240,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1240,8 +1240,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
); );
} }
..onPopRoute = () { ..onPopRoute = () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped outer', uri: Uri.parse('popped outer'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}; };
...@@ -1270,35 +1270,35 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1270,35 +1270,35 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
final List<RouteInformation> reportedRouteInformation = <RouteInformation>[]; final List<RouteInformation> reportedRouteInformation = <RouteInformation>[];
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider( final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(
onRouterReport: (RouteInformation info, RouteInformationReportingType type) => reportedRouteInformation.add(info), onRouterReport: (RouteInformation info, RouteInformationReportingType type) => reportedRouteInformation.add(info),
)..value = const RouteInformation(location: '/home'); )..value = RouteInformation(uri: Uri.parse('/home'));
await tester.pumpWidget(buildBoilerPlate( await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>( Router<RouteInformation>(
routeInformationProvider: provider, routeInformationProvider: provider,
routeInformationParser: RedirectingInformationParser(<String, RouteInformation>{ routeInformationParser: RedirectingInformationParser(<String, RouteInformation>{
'/doesNotExist' : const RouteInformation(location: '/404'), '/doesNotExist' : RouteInformation(uri: Uri.parse('/404')),
}), }),
routerDelegate: SimpleRouterDelegate( routerDelegate: SimpleRouterDelegate(
builder: (BuildContext _, RouteInformation? info) => Text('Current route: ${info?.location}'), builder: (BuildContext _, RouteInformation? info) => Text('Current route: ${info?.uri}'),
reportConfiguration: true, reportConfiguration: true,
), ),
), ),
)); ));
expect(find.text('Current route: /home'), findsOneWidget); expect(find.text('Current route: /home'), findsOneWidget);
expect(reportedRouteInformation.single.location, '/home'); expect(reportedRouteInformation.single.uri.toString(), '/home');
provider.value = const RouteInformation(location: '/doesNotExist'); provider.value = RouteInformation(uri: Uri.parse('/doesNotExist'));
await tester.pump(); await tester.pump();
expect(find.text('Current route: /404'), findsOneWidget); expect(find.text('Current route: /404'), findsOneWidget);
expect(reportedRouteInformation[1].location, '/404'); expect(reportedRouteInformation[1].uri.toString(), '/404');
}); });
testWidgets('RouterInformationParser can look up dependencies and reparse', (WidgetTester tester) async { testWidgets('RouterInformationParser can look up dependencies and reparse', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher dispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher dispatcher = RootBackButtonDispatcher();
int expectedMaxLines = 1; int expectedMaxLines = 1;
...@@ -1308,15 +1308,15 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1308,15 +1308,15 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
routeInformationParser: CustomRouteInformationParser((RouteInformation information, BuildContext context) { routeInformationParser: CustomRouteInformationParser((RouteInformation information, BuildContext context) {
parserCalled = true; parserCalled = true;
final DefaultTextStyle style = DefaultTextStyle.of(context); final DefaultTextStyle style = DefaultTextStyle.of(context);
return RouteInformation(location: '${style.maxLines}'); return RouteInformation(uri: Uri.parse('${style.maxLines}'));
}), }),
routerDelegate: SimpleRouterDelegate( routerDelegate: SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) { builder: (BuildContext context, RouteInformation? information) {
return Text(information!.location!); return Text(Uri.decodeComponent(information!.uri.toString()));
}, },
onPopRoute: () { onPopRoute: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -1350,8 +1350,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1350,8 +1350,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
testWidgets('RouterInformationParser can look up dependencies without reparsing', (WidgetTester tester) async { testWidgets('RouterInformationParser can look up dependencies without reparsing', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher dispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher dispatcher = RootBackButtonDispatcher();
const int expectedMaxLines = 1; const int expectedMaxLines = 1;
...@@ -1361,15 +1361,15 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1361,15 +1361,15 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
routeInformationParser: CustomRouteInformationParser((RouteInformation information, BuildContext context) { routeInformationParser: CustomRouteInformationParser((RouteInformation information, BuildContext context) {
parserCalled = true; parserCalled = true;
final DefaultTextStyle style = context.getInheritedWidgetOfExactType<DefaultTextStyle>()!; final DefaultTextStyle style = context.getInheritedWidgetOfExactType<DefaultTextStyle>()!;
return RouteInformation(location: '${style.maxLines}'); return RouteInformation(uri: Uri.parse('${style.maxLines}'));
}), }),
routerDelegate: SimpleRouterDelegate( routerDelegate: SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) { builder: (BuildContext context, RouteInformation? information) {
return Text(information!.location!); return Text(Uri.decodeComponent(information!.uri.toString()));
}, },
onPopRoute: () { onPopRoute: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -1405,8 +1405,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1405,8 +1405,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
testWidgets('Looks up dependencies in RouterDelegate does not trigger re-parsing', (WidgetTester tester) async { testWidgets('Looks up dependencies in RouterDelegate does not trigger re-parsing', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(); final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'initial', uri: Uri.parse('initial'),
); );
final BackButtonDispatcher dispatcher = RootBackButtonDispatcher(); final BackButtonDispatcher dispatcher = RootBackButtonDispatcher();
int expectedMaxLines = 1; int expectedMaxLines = 1;
...@@ -1423,8 +1423,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1423,8 +1423,8 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
return Text('${style.maxLines}'); return Text('${style.maxLines}');
}, },
onPopRoute: () { onPopRoute: () {
provider.value = const RouteInformation( provider.value = RouteInformation(
location: 'popped', uri: Uri.parse('popped'),
); );
return SynchronousFuture<bool>(true); return SynchronousFuture<bool>(true);
}, },
...@@ -1460,7 +1460,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1460,7 +1460,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
testWidgets('Router can initialize with RouterConfig', (WidgetTester tester) async { testWidgets('Router can initialize with RouterConfig', (WidgetTester tester) async {
const String expected = 'text'; const String expected = 'text';
final RouterConfig<RouteInformation> config = RouterConfig<RouteInformation>( final RouterConfig<RouteInformation> config = RouterConfig<RouteInformation>(
routeInformationProvider: SimpleRouteInformationProvider()..value = const RouteInformation(location: '/'), routeInformationProvider: SimpleRouteInformationProvider()..value = RouteInformation(uri: Uri.parse('/')),
routeInformationParser: SimpleRouteInformationParser(), routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleRouterDelegate( routerDelegate: SimpleRouterDelegate(
builder: (_, __) => const Text(expected), builder: (_, __) => const Text(expected),
...@@ -1477,6 +1477,41 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ...@@ -1477,6 +1477,41 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(find.text(expected), findsOneWidget); expect(find.text(expected), findsOneWidget);
}); });
group('RouteInformation uri api', () {
test('can produce correct uri from location', () async {
final RouteInformation info1 = RouteInformation(uri: Uri.parse('/a?abc=def&abc=jkl#mno'));
expect(info1.location, '/a?abc=def&abc=jkl#mno');
final Uri uri1 = info1.uri;
expect(uri1.scheme, '');
expect(uri1.host, '');
expect(uri1.path, '/a');
expect(uri1.fragment, 'mno');
expect(uri1.queryParametersAll.length, 1);
expect(uri1.queryParametersAll['abc']!.length, 2);
expect(uri1.queryParametersAll['abc']![0], 'def');
expect(uri1.queryParametersAll['abc']![1], 'jkl');
final RouteInformation info2 = RouteInformation(uri: Uri.parse('1'));
expect(info2.location, '1');
final Uri uri2 = info2.uri;
expect(uri2.scheme, '');
expect(uri2.host, '');
expect(uri2.path, '1');
expect(uri2.fragment, '');
expect(uri2.queryParametersAll.length, 0);
});
test('can produce correct location from uri', () async {
final RouteInformation info1 = RouteInformation(uri: Uri.parse('http://mydomain.com'));
expect(info1.uri.toString(), 'http://mydomain.com');
expect(info1.location, '/');
final RouteInformation info2 = RouteInformation(uri: Uri.parse('http://mydomain.com/abc?def=ghi&def=jkl#mno'));
expect(info2.uri.toString(), 'http://mydomain.com/abc?def=ghi&def=jkl#mno');
expect(info2.location, '/abc?def=ghi&def=jkl#mno');
});
});
} }
Widget buildBoilerPlate(Widget child) { Widget buildBoilerPlate(Widget child) {
...@@ -1605,7 +1640,7 @@ class SimpleNavigatorRouterDelegate extends RouterDelegate<RouteInformation> wit ...@@ -1605,7 +1640,7 @@ class SimpleNavigatorRouterDelegate extends RouterDelegate<RouteInformation> wit
child: Text('base'), child: Text('base'),
), ),
MaterialPage<void>( MaterialPage<void>(
key: ValueKey<String>(routeInformation.location!), key: ValueKey<String>(routeInformation.uri.toString()),
child: builder(context, routeInformation), child: builder(context, routeInformation),
), ),
], ],
...@@ -1707,7 +1742,7 @@ class RedirectingInformationParser extends RouteInformationParser<RouteInformati ...@@ -1707,7 +1742,7 @@ class RedirectingInformationParser extends RouteInformationParser<RouteInformati
@override @override
Future<RouteInformation> parseRouteInformation(RouteInformation information) { Future<RouteInformation> parseRouteInformation(RouteInformation information) {
return SynchronousFuture<RouteInformation>(redirects[information.location] ?? information); return SynchronousFuture<RouteInformation>(redirects[information.uri.toString()] ?? information);
} }
@override @override
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment