diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 7051937c2e9..005400fc761 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -2132,9 +2132,17 @@ class Navigator extends StatefulWidget { bool rootNavigator = false, bool nullOk = false, }) { - final NavigatorState navigator = rootNavigator - ? context.findRootAncestorStateOfType() - : context.findAncestorStateOfType(); + // Handles the case where the input context is a navigator element. + NavigatorState navigator; + if (context is StatefulElement && context.state is NavigatorState) { + navigator = context.state as NavigatorState; + } + if (rootNavigator) { + navigator = context.findRootAncestorStateOfType() ?? navigator; + } else { + navigator = navigator ?? context.findAncestorStateOfType(); + } + assert(() { if (navigator == null && !nullOk) { throw FlutterError( diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart index 57153d12cbd..5d847105b23 100644 --- a/packages/flutter/test/material/dialog_test.dart +++ b/packages/flutter/test/material/dialog_test.dart @@ -257,6 +257,46 @@ void main() { expect(await result, equals(42)); }); + testWidgets('Can show dialog using navigator global key', (WidgetTester tester) async { + final GlobalKey navigator = GlobalKey(); + await tester.pumpWidget( + MaterialApp( + navigatorKey: navigator, + home: const Material( + child: Center( + child: Text('Go'), + ), + ), + ), + ); + + final Future result = showDialog( + context: navigator.currentContext, + builder: (BuildContext context) { + return SimpleDialog( + title: const Text('Title'), + children: [ + SimpleDialogOption( + onPressed: () { + Navigator.pop(context, 42); + }, + child: const Text('First option'), + ), + const SimpleDialogOption( + child: Text('Second option'), + ), + ], + ); + }, + ); + + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('Title'), findsOneWidget); + await tester.tap(find.text('First option')); + + expect(await result, equals(42)); + }); + testWidgets('Custom padding on SimpleDialogOption', (WidgetTester tester) async { const EdgeInsets customPadding = EdgeInsets.fromLTRB(4, 10, 8, 6); final SimpleDialog dialog = SimpleDialog( diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index 1da898c5a39..b534e360d75 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -1753,6 +1753,41 @@ void main() { expect(find.text('World'), findsNothing); }); + testWidgets('Navigator.of able to handle input context is a navigator context', (WidgetTester tester) async { + final GlobalKey g = GlobalKey(); + await tester.pumpWidget( + MaterialApp( + navigatorKey: g, + home: const Text('home'), + ) + ); + + final NavigatorState state = Navigator.of(g.currentContext); + expect(state, g.currentState); + }); + + testWidgets('Navigator.of able to handle input context is a navigator context - root navigator', (WidgetTester tester) async { + final GlobalKey root = GlobalKey(); + final GlobalKey sub = GlobalKey(); + await tester.pumpWidget( + MaterialApp( + navigatorKey: root, + home: Navigator( + key: sub, + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + settings: settings, + builder: (BuildContext context) => const Text('dummy'), + ); + }, + ), + ) + ); + + final NavigatorState state = Navigator.of(sub.currentContext, rootNavigator: true); + expect(state, root.currentState); + }); + testWidgets('pushAndRemove until animates the push', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/25080.