From 57e81894b2ac61b20412b5b9afcde632144cfc34 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Thu, 23 Jan 2020 20:23:02 -0800 Subject: [PATCH] Guard against a null navigator on popping a route. (#49329) --- .../flutter/lib/src/widgets/navigator.dart | 2 +- .../flutter/test/widgets/navigator_test.dart | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index a8d0f9bf23..e624cc5bc9 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -136,7 +136,7 @@ abstract class Route { @mustCallSuper TickerFuture didPush() { return TickerFuture.complete()..then((void _) { - navigator.focusScopeNode.requestFocus(); + navigator?.focusScopeNode?.requestFocus(); }); } diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index 5522c1179d..9f87b52e58 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -1036,6 +1036,54 @@ void main() { expect(find.byKey(keyAB), findsNothing); }); + testWidgets("Popping immediately after pushing doesn't crash", (WidgetTester tester) async { + // Added this test to protect against regression of https://github.com/flutter/flutter/issues/45539 + final Map routes = { + '/' : (BuildContext context) => OnTapPage(id: '/', onTap: () { + Navigator.pushNamed(context, '/A'); + Navigator.of(context).pop(); + }), + '/A': (BuildContext context) => OnTapPage(id: 'A', onTap: () { Navigator.pop(context); }), + }; + bool isPushed = false; + bool isPopped = false; + final TestObserver observer = TestObserver() + ..onPushed = (Route route, Route previousRoute) { + // Pushes the initial route. + expect(route is PageRoute && route.settings.name == '/', isTrue); + expect(previousRoute, isNull); + isPushed = true; + } + ..onPopped = (Route route, Route previousRoute) { + isPopped = true; + }; + + await tester.pumpWidget(MaterialApp( + routes: routes, + navigatorObservers: [observer], + )); + expect(find.text('/'), findsOneWidget); + expect(find.text('A'), findsNothing); + expect(isPushed, isTrue); + expect(isPopped, isFalse); + + isPushed = false; + isPopped = false; + observer.onPushed = (Route route, Route previousRoute) { + expect(route is PageRoute && route.settings.name == '/A', isTrue); + expect(previousRoute is PageRoute && previousRoute.settings.name == '/', isTrue); + isPushed = true; + }; + + await tester.tap(find.text('/')); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); + expect(find.text('/'), findsOneWidget); + expect(find.text('A'), findsNothing); + expect(isPushed, isTrue); + expect(isPopped, isTrue); + }); + group('error control test', () { testWidgets('onUnknownRoute null and onGenerateRoute returns null', (WidgetTester tester) async { final GlobalKey navigatorKey = GlobalKey();