Unverified Commit 2c3db435 authored by Kostia Sokolovskyi's avatar Kostia Sokolovskyi Committed by GitHub

_RouterState should dispose created _RestorableRouteInformation. (#136556)

### Description
- Fixes https://github.com/flutter/flutter/issues/134205.

### Tests
- Removes ignoring the `_RestorableRouteInformation` leak from `cupertino/app_test.dart`;
- Removes ignoring the `_RestorableRouteInformation` leak from `material/app_test.dart`;
- Removes ignoring the `_RestorableRouteInformation` leak from `widgets/app_test.dart`;
- Removes ignoring the `_RestorableRouteInformation` leak from `widgets/route_notification_messages_test.dart`;
- Removes ignoring the `_RestorableRouteInformation` leak from `widgets/router_restoration_test.dart`;
- Updates `widgets/router_test.dart` to use `testWidgetsWithLeakTracking`.
parent 5b7e9d60
......@@ -632,6 +632,10 @@ class _RouterState<T> extends State<Router<T>> with RestorationMixin {
}
void _reportRouteInformation(Duration timestamp) {
if (!mounted) {
return;
}
assert(_routeInformationReportingTaskScheduled);
_routeInformationReportingTaskScheduled = false;
......@@ -726,6 +730,7 @@ class _RouterState<T> extends State<Router<T>> with RestorationMixin {
@override
void dispose() {
_routeInformation.dispose();
widget.routeInformationProvider?.removeListener(_handleRouteInformationProviderNotification);
widget.backButtonDispatcher?.removeCallback(_handleBackButtonDispatcherNotification);
widget.routerDelegate.removeListener(_handleRouterDelegateNotification);
......
......@@ -178,12 +178,7 @@ void main() {
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
await tester.pumpAndSettle();
expect(find.text('popped'), findsOneWidget);
},
// TODO(polina-c): remove after fixing
// https://github.com/flutter/flutter/issues/134205
leakTrackingTestConfig: const LeakTrackingTestConfig(
allowAllNotDisposed: true,
));
});
testWidgetsWithLeakTracking('CupertinoApp.router route information parser is optional', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
......@@ -209,12 +204,7 @@ void main() {
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
await tester.pumpAndSettle();
expect(find.text('popped'), findsOneWidget);
},
// TODO(polina-c): remove after fixing
// https://github.com/flutter/flutter/issues/134205
leakTrackingTestConfig: const LeakTrackingTestConfig(
allowAllNotDisposed: true,
));
});
testWidgetsWithLeakTracking('CupertinoApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
......@@ -300,12 +290,7 @@ void main() {
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
await tester.pumpAndSettle();
expect(find.text('popped'), findsOneWidget);
},
// TODO(polina-c): remove after fixing
// https://github.com/flutter/flutter/issues/134205
leakTrackingTestConfig: const LeakTrackingTestConfig(
allowAllNotDisposed: true,
));
});
testWidgetsWithLeakTracking('CupertinoApp has correct default ScrollBehavior', (WidgetTester tester) async {
late BuildContext capturedContext;
......
......@@ -1114,12 +1114,7 @@ void main() {
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
await tester.pumpAndSettle();
expect(find.text('popped'), findsOneWidget);
},
// TODO(polina-c): remove after fixing
// https://github.com/flutter/flutter/issues/134205
leakTrackingTestConfig: const LeakTrackingTestConfig(
allowAllNotDisposed: true,
));
});
testWidgetsWithLeakTracking('MaterialApp.router route information parser is optional', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
......@@ -1145,12 +1140,7 @@ void main() {
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
await tester.pumpAndSettle();
expect(find.text('popped'), findsOneWidget);
},
// TODO(polina-c): remove after fixing
// https://github.com/flutter/flutter/issues/134205
leakTrackingTestConfig: const LeakTrackingTestConfig(
allowAllNotDisposed: true,
));
});
testWidgetsWithLeakTracking('MaterialApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
......@@ -1236,12 +1226,7 @@ void main() {
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
await tester.pumpAndSettle();
expect(find.text('popped'), findsOneWidget);
},
// TODO(polina-c): remove after fixing
// https://github.com/flutter/flutter/issues/134205
leakTrackingTestConfig: const LeakTrackingTestConfig(
allowAllNotDisposed: true,
));
});
testWidgetsWithLeakTracking('MaterialApp.builder can build app without a Navigator', (WidgetTester tester) async {
Widget? builderChild;
......
......@@ -304,12 +304,7 @@ void main() {
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
await tester.pumpAndSettle();
expect(find.text('popped'), findsOneWidget);
},
leakTrackingTestConfig: const LeakTrackingTestConfig(
// TODO(ksokolovskyi): remove after fixing
// https://github.com/flutter/flutter/issues/134205
notDisposedAllowList: <String, int?> {'_RestorableRouteInformation': 1},
));
});
testWidgetsWithLeakTracking('WidgetsApp.router route information parser is optional', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
......@@ -336,12 +331,7 @@ void main() {
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
await tester.pumpAndSettle();
expect(find.text('popped'), findsOneWidget);
},
leakTrackingTestConfig: const LeakTrackingTestConfig(
// TODO(ksokolovskyi): remove after fixing
// https://github.com/flutter/flutter/issues/134205
notDisposedAllowList: <String, int?> {'_RestorableRouteInformation': 1},
));
});
testWidgetsWithLeakTracking('WidgetsApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
......@@ -432,12 +422,7 @@ void main() {
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { });
await tester.pumpAndSettle();
expect(find.text('popped'), findsOneWidget);
},
leakTrackingTestConfig: const LeakTrackingTestConfig(
// TODO(ksokolovskyi): remove after fixing
// https://github.com/flutter/flutter/issues/134205
notDisposedAllowList: <String, int?> {'_RestorableRouteInformation': 1},
));
});
testWidgetsWithLeakTracking('WidgetsApp.router has correct default', (WidgetTester tester) async {
final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate(
......@@ -453,12 +438,7 @@ void main() {
color: const Color(0xFF123456),
));
expect(find.text('/'), findsOneWidget);
},
leakTrackingTestConfig: const LeakTrackingTestConfig(
// TODO(ksokolovskyi): remove after fixing
// https://github.com/flutter/flutter/issues/134205
notDisposedAllowList: <String, int?> {'_RestorableRouteInformation': 1},
));
});
testWidgetsWithLeakTracking('WidgetsApp has correct default ScrollBehavior', (WidgetTester tester) async {
late BuildContext capturedContext;
......
......@@ -316,12 +316,7 @@ void main() {
'replace': false,
}),
]);
},
leakTrackingTestConfig: const LeakTrackingTestConfig(
// TODO(ksokolovskyi): remove after fixing
// https://github.com/flutter/flutter/issues/134205
notDisposedAllowList: <String, int?> {'_RestorableRouteInformation': 1},
));
});
}
typedef SimpleRouterDelegateBuilder = Widget Function(BuildContext, RouteInformation);
......
......@@ -40,12 +40,7 @@ void main() {
expect(find.text('Current config: /foo'), findsOneWidget);
expect(delegate().newRoutePaths, isEmpty);
expect(delegate().restoredRoutePaths, <String>['/foo', '/foo']);
},
leakTrackingTestConfig: const LeakTrackingTestConfig(
// TODO(ksokolovskyi): remove after fixing
// https://github.com/flutter/flutter/issues/134205
notDisposedAllowList: <String, int?> {'_RestorableRouteInformation': 2},
));
});
testWidgets('Router state restoration with RouteInformationProvider', (WidgetTester tester) async {
final UniqueKey router = UniqueKey();
......
......@@ -11,20 +11,24 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() {
testWidgets('Simple router basic functionality - synchronized', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Simple router basic functionality - synchronized', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
return Text(Uri.decodeComponent(information!.uri.toString()));
},
);
addTearDown(delegate.dispose);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
return Text(Uri.decodeComponent(information!.uri.toString()));
},
),
routerDelegate: delegate,
),
));
expect(find.text('initial'), findsOneWidget);
......@@ -37,8 +41,9 @@ void main() {
expect(find.text('update'), findsOneWidget);
});
testWidgets('Simple router basic functionality - asynchronized', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Simple router basic functionality - asynchronized', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
......@@ -51,6 +56,8 @@ void main() {
return Text(information.uri.toString());
},
);
addTearDown(delegate.dispose);
await tester.runAsync(() async {
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
......@@ -81,8 +88,9 @@ void main() {
});
});
testWidgets('Interrupts route parsing should not crash', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Interrupts route parsing should not crash', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
......@@ -95,6 +103,8 @@ void main() {
return Text(information.uri.toString());
},
);
addTearDown(delegate.dispose);
await tester.runAsync(() async {
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
......@@ -130,7 +140,7 @@ void main() {
});
});
testWidgets('Router.maybeOf can be null', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Router.maybeOf can be null', (WidgetTester tester) async {
final GlobalKey key = GlobalKey();
await tester.pumpWidget(buildBoilerPlate(
Text('dummy', key: key),
......@@ -147,18 +157,14 @@ void main() {
);
});
testWidgets('Simple router can handle pop route', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Simple router can handle pop route', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final BackButtonDispatcher dispatcher = RootBackButtonDispatcher();
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleRouterDelegate(
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
return Text(Uri.decodeComponent(information!.uri.toString()));
},
......@@ -168,7 +174,14 @@ void main() {
);
return SynchronousFuture<bool>(true);
},
),
);
addTearDown(delegate.dispose);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: delegate,
backButtonDispatcher: dispatcher,
),
));
......@@ -186,20 +199,24 @@ void main() {
expect(find.text('popped'), findsOneWidget);
});
testWidgets('Router throw when passing routeInformationProvider without routeInformationParser', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Router throw when passing routeInformationProvider without routeInformationParser', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
return Text(Uri.decodeComponent(information!.uri.toString()));
},
);
addTearDown(delegate.dispose);
expect(
() {
Router<RouteInformation>(
routeInformationProvider: provider,
routerDelegate: SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
return Text(Uri.decodeComponent(information!.uri.toString()));
},
),
routerDelegate: delegate,
);
},
throwsA(isAssertionError.having(
......@@ -210,8 +227,9 @@ void main() {
);
});
testWidgets('PopNavigatorRouterDelegateMixin works', (WidgetTester tester) async {
testWidgetsWithLeakTracking('PopNavigatorRouterDelegateMixin works', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
......@@ -227,6 +245,8 @@ void main() {
return route.didPop(result);
},
);
addTearDown(delegate.dispose);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
routeInformationProvider: provider,
......@@ -263,25 +283,18 @@ void main() {
expect(find.text('popped'), findsOneWidget);
});
testWidgets('Nested routers back button dispatcher works', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Nested routers back button dispatcher works', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleRouterDelegate(
final SimpleRouterDelegate outerDelegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
final BackButtonDispatcher innerDispatcher = ChildBackButtonDispatcher(outerDispatcher);
innerDispatcher.takePriority();
// Creates the sub-router.
return Router<RouteInformation>(
backButtonDispatcher: innerDispatcher,
routerDelegate: SimpleRouterDelegate(
final SimpleRouterDelegate innerDelegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? innerInformation) {
return Text(Uri.decodeComponent(information!.uri.toString()));
},
......@@ -291,7 +304,12 @@ void main() {
);
return SynchronousFuture<bool>(true);
},
),
);
addTearDown(innerDelegate.dispose);
// Creates the sub-router.
return Router<RouteInformation>(
backButtonDispatcher: innerDispatcher,
routerDelegate: innerDelegate,
);
},
onPopRoute: () {
......@@ -300,7 +318,15 @@ void main() {
);
return SynchronousFuture<bool>(true);
},
),
);
addTearDown(outerDelegate.dispose);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: outerDelegate,
),
));
expect(find.text('initial'), findsOneWidget);
......@@ -313,28 +339,29 @@ void main() {
expect(find.text('popped inner'), findsOneWidget);
});
testWidgets('Nested router back button dispatcher works for multiple children', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Nested router back button dispatcher works for multiple children', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
final BackButtonDispatcher innerDispatcher1 = ChildBackButtonDispatcher(outerDispatcher);
final BackButtonDispatcher innerDispatcher2 = ChildBackButtonDispatcher(outerDispatcher);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleRouterDelegate(
final SimpleRouterDelegate outerDelegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
late final SimpleRouterDelegate innerDelegate1;
addTearDown(() => innerDelegate1.dispose());
late final SimpleRouterDelegate innerDelegate2;
addTearDown(() => innerDelegate2.dispose());
// Creates the sub-router.
return Column(
children: <Widget>[
Text(Uri.decodeComponent(information!.uri.toString())),
Router<RouteInformation>(
backButtonDispatcher: innerDispatcher1,
routerDelegate: SimpleRouterDelegate(
routerDelegate: innerDelegate1 = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? innerInformation) {
return Container();
},
......@@ -348,7 +375,7 @@ void main() {
),
Router<RouteInformation>(
backButtonDispatcher: innerDispatcher2,
routerDelegate: SimpleRouterDelegate(
routerDelegate: innerDelegate2 = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? innerInformation) {
return Container();
},
......@@ -369,7 +396,15 @@ void main() {
);
return SynchronousFuture<bool>(true);
},
),
);
addTearDown(outerDelegate.dispose);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: outerDelegate,
),
));
expect(find.text('initial'), findsOneWidget);
......@@ -398,88 +433,107 @@ void main() {
expect(find.text('popped inner2'), findsOneWidget);
});
testWidgets('ChildBackButtonDispatcher can be replaced without calling the takePriority', (WidgetTester tester) async {
testWidgetsWithLeakTracking('ChildBackButtonDispatcher can be replaced without calling the takePriority', (WidgetTester tester) async {
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
BackButtonDispatcher innerDispatcher = ChildBackButtonDispatcher(outerDispatcher);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routerDelegate: SimpleRouterDelegate(
final SimpleRouterDelegate outerDelegate1 = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
final SimpleRouterDelegate innerDelegate1 = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? innerInformation) {
return Container();
},
);
addTearDown(innerDelegate1.dispose);
// Creates the sub-router.
return Column(
children: <Widget>[
const Text('initial'),
Router<RouteInformation>(
backButtonDispatcher: innerDispatcher,
routerDelegate: SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? innerInformation) {
return Container();
},
),
routerDelegate: innerDelegate1,
),
],
);
},
),
);
addTearDown(outerDelegate1.dispose);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routerDelegate: outerDelegate1,
),
));
// Creates a new child back button dispatcher and rebuild, this will cause
// the old one to be replaced and discarded.
innerDispatcher = ChildBackButtonDispatcher(outerDispatcher);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routerDelegate: SimpleRouterDelegate(
final SimpleRouterDelegate outerDelegate2 = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
final SimpleRouterDelegate innerDelegate2 = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? innerInformation) {
return Container();
},
);
addTearDown(innerDelegate2.dispose);
// Creates the sub-router.
return Column(
children: <Widget>[
const Text('initial'),
Router<RouteInformation>(
backButtonDispatcher: innerDispatcher,
routerDelegate: SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? innerInformation) {
return Container();
},
),
routerDelegate: innerDelegate2,
),
],
);
},
),
);
addTearDown(outerDelegate2.dispose);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routerDelegate: outerDelegate2,
),
));
expect(tester.takeException(), isNull);
});
testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester tester) async {
testWidgetsWithLeakTracking('ChildBackButtonDispatcher take priority recursively', (WidgetTester tester) async {
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
final BackButtonDispatcher innerDispatcher1 = ChildBackButtonDispatcher(outerDispatcher);
final BackButtonDispatcher innerDispatcher2 = ChildBackButtonDispatcher(innerDispatcher1);
final BackButtonDispatcher innerDispatcher3 = ChildBackButtonDispatcher(innerDispatcher2);
late final SimpleRouterDelegate outerDelegate;
addTearDown(() => outerDelegate.dispose());
late final SimpleRouterDelegate innerDelegate1;
addTearDown(() => innerDelegate1.dispose());
late final SimpleRouterDelegate innerDelegate2;
addTearDown(() => innerDelegate2.dispose());
late final SimpleRouterDelegate innerDelegate3;
addTearDown(() => innerDelegate3.dispose());
bool isPopped = false;
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routerDelegate: SimpleRouterDelegate(
routerDelegate: outerDelegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
// Creates the sub-router.
return Router<RouteInformation>(
backButtonDispatcher: innerDispatcher1,
routerDelegate: SimpleRouterDelegate(
routerDelegate: innerDelegate1 = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? innerInformation) {
return Router<RouteInformation>(
backButtonDispatcher: innerDispatcher2,
routerDelegate: SimpleRouterDelegate(
routerDelegate: innerDelegate2 = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? innerInformation) {
return Router<RouteInformation>(
backButtonDispatcher: innerDispatcher3,
routerDelegate: SimpleRouterDelegate(
routerDelegate: innerDelegate3 = SimpleRouterDelegate(
onPopRoute: () {
isPopped = true;
return SynchronousFuture<bool>(true);
......@@ -508,7 +562,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(isPopped, isTrue);
});
testWidgets('router does report URL change correctly', (WidgetTester tester) async {
testWidgetsWithLeakTracking('router does report URL change correctly', (WidgetTester tester) async {
RouteInformation? reportedRouteInformation;
RouteInformationReportingType? reportedType;
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(
......@@ -520,6 +574,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
reportedType = type;
},
);
addTearDown(provider.dispose);
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
reportConfiguration: true,
builder: (BuildContext context, RouteInformation? information) {
......@@ -532,6 +587,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
);
return SynchronousFuture<bool>(true);
};
addTearDown(delegate.dispose);
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
provider.value = RouteInformation(
......@@ -584,7 +640,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(reportedType, RouteInformationReportingType.none);
});
testWidgets('router can be forced to recognize or ignore navigating events', (WidgetTester tester) async {
testWidgetsWithLeakTracking('router can be forced to recognize or ignore navigating events', (WidgetTester tester) async {
RouteInformation? reportedRouteInformation;
RouteInformationReportingType? reportedType;
bool isNavigating = false;
......@@ -598,10 +654,12 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
reportedType = type;
},
);
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final SimpleRouterDelegate delegate = SimpleRouterDelegate(reportConfiguration: true);
addTearDown(delegate.dispose);
delegate.builder = (BuildContext context, RouteInformation? information) {
return ElevatedButton(
child: Text(Uri.decodeComponent(information!.uri.toString())),
......@@ -662,7 +720,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
reportedRouteInformation = null;
});
testWidgets('router ignore navigating events updates RouteInformationProvider', (WidgetTester tester) async {
testWidgetsWithLeakTracking('router ignore navigating events updates RouteInformationProvider', (WidgetTester tester) async {
RouteInformation? updatedRouteInformation;
late RouteInformation nextRouteInformation;
RouteInformationReportingType? reportingType;
......@@ -674,10 +732,12 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
reportingType = type;
},
);
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final SimpleRouterDelegate delegate = SimpleRouterDelegate(reportConfiguration: true);
addTearDown(delegate.dispose);
delegate.builder = (BuildContext context, RouteInformation? information) {
return ElevatedButton(
child: Text(Uri.decodeComponent(information!.uri.toString())),
......@@ -717,7 +777,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(reportingType, RouteInformationReportingType.neglect);
});
testWidgets('state change without location changes updates RouteInformationProvider', (WidgetTester tester) async {
testWidgetsWithLeakTracking('state change without location changes updates RouteInformationProvider', (WidgetTester tester) async {
RouteInformation? updatedRouteInformation;
late RouteInformation nextRouteInformation;
RouteInformationReportingType? reportingType;
......@@ -730,11 +790,13 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
reportingType = type;
},
);
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
state: 'state1',
);
final SimpleRouterDelegate delegate = SimpleRouterDelegate(reportConfiguration: true);
addTearDown(delegate.dispose);
delegate.builder = (BuildContext context, RouteInformation? information) {
return ElevatedButton(
child: Text(Uri.decodeComponent(information!.uri.toString())),
......@@ -770,12 +832,13 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(reportingType, RouteInformationReportingType.none);
});
testWidgets('PlatformRouteInformationProvider works', (WidgetTester tester) async {
final RouteInformationProvider provider = PlatformRouteInformationProvider(
testWidgetsWithLeakTracking('PlatformRouteInformationProvider works', (WidgetTester tester) async {
final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: RouteInformation(
uri: Uri.parse('initial'),
),
);
addTearDown(provider.dispose);
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
final List<Widget> children = <Widget>[];
......@@ -790,6 +853,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
);
},
);
addTearDown(delegate.dispose);
await tester.pumpWidget(MaterialApp.router(
routeInformationProvider: provider,
......@@ -821,7 +885,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(find.text('newTestRouteName'), findsOneWidget);
});
testWidgets('PlatformRouteInformationProvider updates route information', (WidgetTester tester) async {
testWidgetsWithLeakTracking('PlatformRouteInformationProvider updates route information', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
TestDefaultBinaryMessengerBinding
.instance.defaultBinaryMessenger
......@@ -832,11 +896,12 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
return null;
}
);
final RouteInformationProvider provider = PlatformRouteInformationProvider(
final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: RouteInformation(
uri: Uri.parse('initial'),
),
);
addTearDown(provider.dispose);
log.clear();
provider.routerReportsNewRouteInformation(RouteInformation(uri: Uri.parse('a'), state: true));
......@@ -868,7 +933,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
]);
});
testWidgets('PlatformRouteInformationProvider does not push new entry if query parameters are semantically the same', (WidgetTester tester) async {
testWidgetsWithLeakTracking('PlatformRouteInformationProvider does not push new entry if query parameters are semantically the same', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
TestDefaultBinaryMessengerBinding
.instance.defaultBinaryMessenger
......@@ -882,9 +947,10 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
final RouteInformation initial = RouteInformation(
uri: Uri.parse('initial?a=ws/abcd'),
);
final RouteInformationProvider provider = PlatformRouteInformationProvider(
final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: initial
);
addTearDown(provider.dispose);
// Make sure engine is updated with initial route
provider.routerReportsNewRouteInformation(initial);
log.clear();
......@@ -938,19 +1004,21 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
log.clear();
});
testWidgets('RootBackButtonDispatcher works', (WidgetTester tester) async {
testWidgetsWithLeakTracking('RootBackButtonDispatcher works', (WidgetTester tester) async {
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
final RouteInformationProvider provider = PlatformRouteInformationProvider(
final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider(
initialRouteInformation: RouteInformation(
uri: Uri.parse('initial'),
),
);
addTearDown(provider.dispose);
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
reportConfiguration: true,
builder: (BuildContext context, RouteInformation? information) {
return Text(Uri.decodeComponent(information!.uri.toString()));
},
);
addTearDown(delegate.dispose);
delegate.onPopRoute = () {
delegate.routeInformation = RouteInformation(
uri: Uri.parse('popped'),
......@@ -973,18 +1041,14 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(find.text('popped'), findsOneWidget);
});
testWidgets('BackButtonListener takes priority over root back dispatcher', (WidgetTester tester) async {
testWidgetsWithLeakTracking('BackButtonListener takes priority over root back dispatcher', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleRouterDelegate(
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
// Creates the sub-router.
return Column(
......@@ -1008,7 +1072,15 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
);
return SynchronousFuture<bool>(true);
},
),
);
addTearDown(delegate.dispose);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: delegate,
),
));
expect(find.text('initial'), findsOneWidget);
......@@ -1020,8 +1092,9 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(find.text('popped inner1'), findsOneWidget);
});
testWidgets('BackButtonListener updates callback if it has been changed', (WidgetTester tester) async {
testWidgetsWithLeakTracking('BackButtonListener updates callback if it has been changed', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
......@@ -1050,6 +1123,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
);
return SynchronousFuture<bool>(true);
};
addTearDown(routerDelegate.dispose);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
......@@ -1099,8 +1173,9 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(find.text('second callback'), findsOneWidget);
});
testWidgets('BackButtonListener clears callback if it is disposed', (WidgetTester tester) async {
testWidgetsWithLeakTracking('BackButtonListener clears callback if it is disposed', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
......@@ -1129,6 +1204,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
);
return SynchronousFuture<bool>(true);
};
addTearDown(routerDelegate.dispose);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
......@@ -1169,18 +1245,13 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(find.text('popped outer'), findsOneWidget);
});
testWidgets('Nested backButtonListener should take priority', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Nested backButtonListener should take priority', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleRouterDelegate(
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
// Creates the sub-router.
return Column(
......@@ -1212,7 +1283,16 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
);
return SynchronousFuture<bool>(true);
},
),
);
addTearDown(delegate.dispose);
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: delegate,
),
));
expect(find.text('initial'), findsOneWidget);
......@@ -1224,18 +1304,13 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(find.text('popped inner2'), findsOneWidget);
});
testWidgets('Nested backButtonListener that returns false should call next on the line', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Nested backButtonListener that returns false should call next on the line', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleRouterDelegate(
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
// Creates the sub-router.
return Column(
......@@ -1267,7 +1342,16 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
);
return SynchronousFuture<bool>(true);
},
),
);
addTearDown(delegate.dispose);
final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher();
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
backButtonDispatcher: outerDispatcher,
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: delegate,
),
));
expect(find.text('initial'), findsOneWidget);
......@@ -1279,8 +1363,9 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(find.text('popped inner1'), findsOneWidget);
});
testWidgets('`didUpdateWidget` test', (WidgetTester tester) async {
testWidgetsWithLeakTracking('`didUpdateWidget` test', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
......@@ -1316,6 +1401,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
);
return SynchronousFuture<bool>(true);
};
addTearDown(routerDelegate.dispose);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
......@@ -1337,11 +1423,17 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(find.text('second callback'), findsOneWidget);
});
testWidgets('Router reports location if it is different from location given by OS', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Router reports location if it is different from location given by OS', (WidgetTester tester) async {
final List<RouteInformation> reportedRouteInformation = <RouteInformation>[];
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider(
onRouterReport: (RouteInformation info, RouteInformationReportingType type) => reportedRouteInformation.add(info),
)..value = RouteInformation(uri: Uri.parse('/home'));
addTearDown(provider.dispose);
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (BuildContext _, RouteInformation? info) => Text('Current route: ${info?.uri}'),
reportConfiguration: true,
);
addTearDown(delegate.dispose);
await tester.pumpWidget(buildBoilerPlate(
Router<RouteInformation>(
......@@ -1349,10 +1441,7 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
routeInformationParser: RedirectingInformationParser(<String, RouteInformation>{
'/doesNotExist' : RouteInformation(uri: Uri.parse('/404')),
}),
routerDelegate: SimpleRouterDelegate(
builder: (BuildContext _, RouteInformation? info) => Text('Current route: ${info?.uri}'),
reportConfiguration: true,
),
routerDelegate: delegate,
),
));
......@@ -1366,22 +1455,14 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(reportedRouteInformation[1].uri.toString(), '/404');
});
testWidgets('RouterInformationParser can look up dependencies and reparse', (WidgetTester tester) async {
testWidgetsWithLeakTracking('RouterInformationParser can look up dependencies and reparse', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final BackButtonDispatcher dispatcher = RootBackButtonDispatcher();
int expectedMaxLines = 1;
bool parserCalled = false;
final Widget router = Router<RouteInformation>(
routeInformationProvider: provider,
routeInformationParser: CustomRouteInformationParser((RouteInformation information, BuildContext context) {
parserCalled = true;
final DefaultTextStyle style = DefaultTextStyle.of(context);
return RouteInformation(uri: Uri.parse('${style.maxLines}'));
}),
routerDelegate: SimpleRouterDelegate(
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
return Text(Uri.decodeComponent(information!.uri.toString()));
},
......@@ -1391,7 +1472,18 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
);
return SynchronousFuture<bool>(true);
},
),
);
addTearDown(delegate.dispose);
int expectedMaxLines = 1;
bool parserCalled = false;
final Widget router = Router<RouteInformation>(
routeInformationProvider: provider,
routeInformationParser: CustomRouteInformationParser((RouteInformation information, BuildContext context) {
parserCalled = true;
final DefaultTextStyle style = DefaultTextStyle.of(context);
return RouteInformation(uri: Uri.parse('${style.maxLines}'));
}),
routerDelegate: delegate,
backButtonDispatcher: dispatcher,
);
await tester.pumpWidget(buildBoilerPlate(
......@@ -1419,22 +1511,14 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(parserCalled, isTrue);
});
testWidgets('RouterInformationParser can look up dependencies without reparsing', (WidgetTester tester) async {
testWidgetsWithLeakTracking('RouterInformationParser can look up dependencies without reparsing', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final BackButtonDispatcher dispatcher = RootBackButtonDispatcher();
const int expectedMaxLines = 1;
bool parserCalled = false;
final Widget router = Router<RouteInformation>(
routeInformationProvider: provider,
routeInformationParser: CustomRouteInformationParser((RouteInformation information, BuildContext context) {
parserCalled = true;
final DefaultTextStyle style = context.getInheritedWidgetOfExactType<DefaultTextStyle>()!;
return RouteInformation(uri: Uri.parse('${style.maxLines}'));
}),
routerDelegate: SimpleRouterDelegate(
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
return Text(Uri.decodeComponent(information!.uri.toString()));
},
......@@ -1444,7 +1528,18 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
);
return SynchronousFuture<bool>(true);
},
),
);
addTearDown(delegate.dispose);
const int expectedMaxLines = 1;
bool parserCalled = false;
final Widget router = Router<RouteInformation>(
routeInformationProvider: provider,
routeInformationParser: CustomRouteInformationParser((RouteInformation information, BuildContext context) {
parserCalled = true;
final DefaultTextStyle style = context.getInheritedWidgetOfExactType<DefaultTextStyle>()!;
return RouteInformation(uri: Uri.parse('${style.maxLines}'));
}),
routerDelegate: delegate,
backButtonDispatcher: dispatcher,
);
await tester.pumpWidget(buildBoilerPlate(
......@@ -1474,21 +1569,14 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(parserCalled, isFalse);
});
testWidgets('Looks up dependencies in RouterDelegate does not trigger re-parsing', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Looks up dependencies in RouterDelegate does not trigger re-parsing', (WidgetTester tester) async {
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(
uri: Uri.parse('initial'),
);
final BackButtonDispatcher dispatcher = RootBackButtonDispatcher();
int expectedMaxLines = 1;
bool parserCalled = false;
final Widget router = Router<RouteInformation>(
routeInformationProvider: provider,
routeInformationParser: CustomRouteInformationParser((RouteInformation information, BuildContext context) {
parserCalled = true;
return information;
}),
routerDelegate: SimpleRouterDelegate(
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (BuildContext context, RouteInformation? information) {
final DefaultTextStyle style = DefaultTextStyle.of(context);
return Text('${style.maxLines}');
......@@ -1499,7 +1587,17 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
);
return SynchronousFuture<bool>(true);
},
),
);
addTearDown(delegate.dispose);
int expectedMaxLines = 1;
bool parserCalled = false;
final Widget router = Router<RouteInformation>(
routeInformationProvider: provider,
routeInformationParser: CustomRouteInformationParser((RouteInformation information, BuildContext context) {
parserCalled = true;
return information;
}),
routerDelegate: delegate,
backButtonDispatcher: dispatcher,
);
await tester.pumpWidget(buildBoilerPlate(
......@@ -1528,14 +1626,19 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester
expect(parserCalled, isFalse);
});
testWidgets('Router can initialize with RouterConfig', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Router can initialize with RouterConfig', (WidgetTester tester) async {
const String expected = 'text';
final SimpleRouteInformationProvider provider = SimpleRouteInformationProvider();
addTearDown(provider.dispose);
provider.value = RouteInformation(uri: Uri.parse('/'));
final SimpleRouterDelegate delegate = SimpleRouterDelegate(
builder: (_, __) => const Text(expected),
);
addTearDown(delegate.dispose);
final RouterConfig<RouteInformation> config = RouterConfig<RouteInformation>(
routeInformationProvider: SimpleRouteInformationProvider()..value = RouteInformation(uri: Uri.parse('/')),
routeInformationProvider: provider,
routeInformationParser: SimpleRouteInformationParser(),
routerDelegate: SimpleRouterDelegate(
builder: (_, __) => const Text(expected),
),
routerDelegate: delegate,
backButtonDispatcher: RootBackButtonDispatcher(),
);
final Router<RouteInformation> router = Router<RouteInformation>.withConfig(config: config);
......
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