Navigator assert on non restorable routes returned by onGenerateInitialRoutes (#73082)
diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 640832a..4beefed 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart
@@ -3388,6 +3388,13 @@ } } + assert( + _history.isNotEmpty, + 'All routes returned by onGenerateInitialRoutes are not restorable. ' + 'Please make sure that all routes returned by onGenerateInitialRoutes ' + 'have their RouteSettings defined with names that are defined in the ' + 'app\'s routes table.', + ); assert(!_debugLocked); assert(() { _debugLocked = true; return true; }()); _flushHistoryUpdates();
diff --git a/packages/flutter/test/widgets/navigator_restoration_test.dart b/packages/flutter/test/widgets/navigator_restoration_test.dart index 3142e8e..f17e6ee 100644 --- a/packages/flutter/test/widgets/navigator_restoration_test.dart +++ b/packages/flutter/test/widgets/navigator_restoration_test.dart
@@ -981,6 +981,44 @@ await tester.pumpAndSettle(); expect(findRoute('p1', count: 0), findsOneWidget); }); + + testWidgets('Helpful assert thrown all routes in onGenerateInitialRoutes are not restorable', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + restorationScopeId: 'material_app', + initialRoute: '/', + routes: <String, WidgetBuilder>{ + '/': (BuildContext context) => Container(), + }, + onGenerateInitialRoutes: (String initialRoute) { + return <MaterialPageRoute<void>>[ + MaterialPageRoute<void>( + builder: (BuildContext context) => Container(), + ), + ]; + }, + ), + ); + await tester.restartAndRestore(); + final dynamic exception = tester.takeException(); + expect(exception, isAssertionError); + expect( + (exception as AssertionError).message, + contains('All routes returned by onGenerateInitialRoutes are not restorable.'), + ); + + // The previous assert leaves the widget tree in a broken state, so the + // following code catches any remaining exceptions from attempting to build + // new widget tree. + final FlutterExceptionHandler? oldHandler = FlutterError.onError; + dynamic remainingException; + FlutterError.onError = (FlutterErrorDetails details) { + remainingException ??= details.exception; + }; + await tester.pumpWidget(Container(key: UniqueKey())); + FlutterError.onError = oldHandler; + expect(remainingException, isAssertionError); + }); } Route<void> _routeBuilder(BuildContext context, Object? arguments) {