diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 23e9927910581..c3ccc0f69dcc9 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -410,7 +410,7 @@ abstract class Route extends _RoutePlaceholder { @mustCallSuper void onPopInvokedWithResult(bool didPop, T? result) { if (_isPageBased) { - final Page page = settings as Page; + final Page page = settings as Page; page.onPopInvoked(didPop, result); } } diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index ac303383d0794..3f1bb6a99154c 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -5352,6 +5352,56 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android }), skip: isBrowser, // [intended] only non-web Android supports predictive back. ); + + testWidgets('canPop and onPopInvoked', (WidgetTester tester) async { + bool page2CanPop = false; + bool page3CanPop = false; + final CanPopPage page1 = CanPopPage(name: 'page1', pageCanPop: () => false); + final CanPopPage page2 = CanPopPage(name: 'page2', pageCanPop: () => page2CanPop); + final CanPopPage page3 = CanPopPage(name: 'page3', pageCanPop: () => page3CanPop); + final List> pages = >[page1, page2, page3]; + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + MaterialApp( + home: Navigator( + key: key, + pages: pages, + onDidRemovePage: (Page page) => pages.remove(page), + ), + ), + ); + + expect(find.text('page3'), findsOneWidget); + + key.currentState!.maybePop(true); + await tester.pumpAndSettle(); + expect(find.text('page3'), findsOneWidget); + expect(page3.popInvoked, [(false, true)]); + + page3CanPop = true; + key.currentState!.maybePop(false); + await tester.pumpAndSettle(); + expect(find.text('page3'), findsNothing); + expect(find.text('page2'), findsOneWidget); + expect(page3.popInvoked, [(false, true), (true, false)]); + + key.currentState!.maybePop('some string'); + await tester.pumpAndSettle(); + expect(find.text('page2'), findsOneWidget); + expect(page2.popInvoked, [(false, 'some string')]); + + page2CanPop = true; + key.currentState!.maybePop('another string'); + await tester.pumpAndSettle(); + expect(find.text('page2'), findsNothing); + expect(find.text('page1'), findsOneWidget); + expect(page2.popInvoked, [(false, 'some string'), (true, 'another string')]); + + key.currentState!.maybePop(1); + await tester.pumpAndSettle(); + expect(find.text('page1'), findsOneWidget); + expect(page1.popInvoked, [(false, 1)]); + }); }); }); } @@ -5487,6 +5537,36 @@ class ZeroTransitionPage extends Page { } } +typedef CanPopPageInvoke = (bool didPop, Object? result); + +class CanPopPage extends Page { + CanPopPage({ + super.key, + super.name, + required this.pageCanPop, + super.arguments, + }); + + final List popInvoked = []; + + @override + bool get canPop => pageCanPop(); + final ValueGetter pageCanPop; + + @override + PopInvokedWithResultCallback get onPopInvoked => (bool didPop, T? result) { + popInvoked.add((didPop, result)); + }; + + @override + Route createRoute(BuildContext context) { + return MaterialPageRoute( + builder: (BuildContext context) => Text(name!), + settings: this, + ); + } +} + class TestPage extends Page { const TestPage({ super.key,