| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter_test/flutter_test.dart'; |
| import 'package:flutter/material.dart'; |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter/gestures.dart'; |
| |
| import '../widgets/semantics_tester.dart'; |
| |
| void main() { |
| // Pumps and ensures that the BottomSheet animates non-linearly. |
| Future<void> _checkNonLinearAnimation(WidgetTester tester) async { |
| final Offset firstPosition = tester.getCenter(find.text('BottomSheet')); |
| await tester.pump(const Duration(milliseconds: 30)); |
| final Offset secondPosition = tester.getCenter(find.text('BottomSheet')); |
| await tester.pump(const Duration(milliseconds: 30)); |
| final Offset thirdPosition = tester.getCenter(find.text('BottomSheet')); |
| |
| final double dyDelta1 = secondPosition.dy - firstPosition.dy; |
| final double dyDelta2 = thirdPosition.dy - secondPosition.dy; |
| |
| // If the animation were linear, these two values would be the same. |
| expect(dyDelta1, isNot(moreOrLessEquals(dyDelta2, epsilon: 0.1))); |
| } |
| |
| testWidgets('Tapping on a modal BottomSheet should not dismiss it', (WidgetTester tester) async { |
| late BuildContext savedContext; |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| home: Builder( |
| builder: (BuildContext context) { |
| savedContext = context; |
| return Container(); |
| }, |
| ), |
| ), |
| ); |
| |
| await tester.pump(); |
| expect(find.text('BottomSheet'), findsNothing); |
| |
| bool showBottomSheetThenCalled = false; |
| showModalBottomSheet<void>( |
| context: savedContext, |
| builder: (BuildContext context) => const Text('BottomSheet'), |
| ).then<void>((void value) { |
| showBottomSheetThenCalled = true; |
| }); |
| |
| await tester.pumpAndSettle(); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| expect(showBottomSheetThenCalled, isFalse); |
| |
| // Tap on the bottom sheet itself, it should not be dismissed |
| await tester.tap(find.text('BottomSheet')); |
| await tester.pumpAndSettle(); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| expect(showBottomSheetThenCalled, isFalse); |
| }); |
| |
| testWidgets('Tapping outside a modal BottomSheet should dismiss it by default', (WidgetTester tester) async { |
| late BuildContext savedContext; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Builder( |
| builder: (BuildContext context) { |
| savedContext = context; |
| return Container(); |
| }, |
| ), |
| )); |
| |
| await tester.pump(); |
| expect(find.text('BottomSheet'), findsNothing); |
| |
| bool showBottomSheetThenCalled = false; |
| showModalBottomSheet<void>( |
| context: savedContext, |
| builder: (BuildContext context) => const Text('BottomSheet'), |
| ).then<void>((void value) { |
| showBottomSheetThenCalled = true; |
| }); |
| |
| await tester.pumpAndSettle(); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| expect(showBottomSheetThenCalled, isFalse); |
| |
| // Tap above the bottom sheet to dismiss it. |
| await tester.tapAt(const Offset(20.0, 20.0)); |
| await tester.pumpAndSettle(); // Bottom sheet dismiss animation. |
| expect(showBottomSheetThenCalled, isTrue); |
| expect(find.text('BottomSheet'), findsNothing); |
| }); |
| |
| testWidgets('Tapping outside a modal BottomSheet should dismiss it when isDismissible=true', (WidgetTester tester) async { |
| late BuildContext savedContext; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Builder( |
| builder: (BuildContext context) { |
| savedContext = context; |
| return Container(); |
| }, |
| ), |
| )); |
| |
| await tester.pump(); |
| expect(find.text('BottomSheet'), findsNothing); |
| |
| bool showBottomSheetThenCalled = false; |
| showModalBottomSheet<void>( |
| context: savedContext, |
| builder: (BuildContext context) => const Text('BottomSheet'), |
| isDismissible: true, |
| ).then<void>((void value) { |
| showBottomSheetThenCalled = true; |
| }); |
| |
| await tester.pumpAndSettle(); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| expect(showBottomSheetThenCalled, isFalse); |
| |
| // Tap above the bottom sheet to dismiss it. |
| await tester.tapAt(const Offset(20.0, 20.0)); |
| await tester.pumpAndSettle(); // Bottom sheet dismiss animation. |
| expect(showBottomSheetThenCalled, isTrue); |
| expect(find.text('BottomSheet'), findsNothing); |
| }); |
| |
| testWidgets('Verify that the BottomSheet animates non-linearly', (WidgetTester tester) async { |
| late BuildContext savedContext; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Builder( |
| builder: (BuildContext context) { |
| savedContext = context; |
| return Container(); |
| }, |
| ), |
| )); |
| |
| await tester.pump(); |
| expect(find.text('BottomSheet'), findsNothing); |
| |
| showModalBottomSheet<void>( |
| context: savedContext, |
| builder: (BuildContext context) => const Text('BottomSheet'), |
| ); |
| await tester.pump(); |
| |
| await _checkNonLinearAnimation(tester); |
| await tester.pumpAndSettle(); |
| |
| // Tap above the bottom sheet to dismiss it. |
| await tester.tapAt(const Offset(20.0, 20.0)); |
| await tester.pump(); |
| await _checkNonLinearAnimation(tester); |
| await tester.pumpAndSettle(); // Bottom sheet dismiss animation. |
| expect(find.text('BottomSheet'), findsNothing); |
| }); |
| |
| testWidgets('Tapping outside a modal BottomSheet should not dismiss it when isDismissible=false', (WidgetTester tester) async { |
| late BuildContext savedContext; |
| |
| await tester.pumpWidget( |
| MaterialApp( |
| home: Builder( |
| builder: (BuildContext context) { |
| savedContext = context; |
| return Container(); |
| }, |
| ), |
| ), |
| ); |
| |
| await tester.pump(); |
| expect(find.text('BottomSheet'), findsNothing); |
| |
| bool showBottomSheetThenCalled = false; |
| showModalBottomSheet<void>( |
| context: savedContext, |
| builder: (BuildContext context) => const Text('BottomSheet'), |
| isDismissible: false, |
| ).then<void>((void value) { |
| showBottomSheetThenCalled = true; |
| }); |
| |
| await tester.pumpAndSettle(); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| expect(showBottomSheetThenCalled, isFalse); |
| |
| // Tap above the bottom sheet, attempting to dismiss it. |
| await tester.tapAt(const Offset(20.0, 20.0)); |
| await tester.pumpAndSettle(); // Bottom sheet should not dismiss. |
| expect(showBottomSheetThenCalled, isFalse); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| }); |
| |
| testWidgets('Swiping down a modal BottomSheet should dismiss it by default', (WidgetTester tester) async { |
| late BuildContext savedContext; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Builder( |
| builder: (BuildContext context) { |
| savedContext = context; |
| return Container(); |
| }, |
| ), |
| )); |
| |
| await tester.pump(); |
| expect(find.text('BottomSheet'), findsNothing); |
| |
| bool showBottomSheetThenCalled = false; |
| showModalBottomSheet<void>( |
| context: savedContext, |
| isDismissible: false, |
| builder: (BuildContext context) => const Text('BottomSheet'), |
| ).then<void>((void value) { |
| showBottomSheetThenCalled = true; |
| }); |
| |
| await tester.pumpAndSettle(); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| expect(showBottomSheetThenCalled, isFalse); |
| |
| // Swipe the bottom sheet to dismiss it. |
| await tester.drag(find.text('BottomSheet'), const Offset(0.0, 150.0)); |
| await tester.pumpAndSettle(); // Bottom sheet dismiss animation. |
| expect(showBottomSheetThenCalled, isTrue); |
| expect(find.text('BottomSheet'), findsNothing); |
| }); |
| |
| testWidgets('Swiping down a modal BottomSheet should not dismiss it when enableDrag is false', (WidgetTester tester) async { |
| late BuildContext savedContext; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Builder( |
| builder: (BuildContext context) { |
| savedContext = context; |
| return Container(); |
| }, |
| ), |
| )); |
| |
| await tester.pump(); |
| expect(find.text('BottomSheet'), findsNothing); |
| |
| bool showBottomSheetThenCalled = false; |
| showModalBottomSheet<void>( |
| context: savedContext, |
| isDismissible: false, |
| enableDrag: false, |
| builder: (BuildContext context) => const Text('BottomSheet'), |
| ).then<void>((void value) { |
| showBottomSheetThenCalled = true; |
| }); |
| |
| await tester.pumpAndSettle(); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| expect(showBottomSheetThenCalled, isFalse); |
| |
| // Swipe the bottom sheet, attempting to dismiss it. |
| await tester.drag(find.text('BottomSheet'), const Offset(0.0, 150.0)); |
| await tester.pumpAndSettle(); // Bottom sheet should not dismiss. |
| expect(showBottomSheetThenCalled, isFalse); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| }); |
| |
| testWidgets('Swiping down a modal BottomSheet should dismiss it when enableDrag is true', (WidgetTester tester) async { |
| late BuildContext savedContext; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Builder( |
| builder: (BuildContext context) { |
| savedContext = context; |
| return Container(); |
| }, |
| ), |
| )); |
| |
| await tester.pump(); |
| expect(find.text('BottomSheet'), findsNothing); |
| |
| bool showBottomSheetThenCalled = false; |
| showModalBottomSheet<void>( |
| context: savedContext, |
| isDismissible: false, |
| enableDrag: true, |
| builder: (BuildContext context) => const Text('BottomSheet'), |
| ).then<void>((void value) { |
| showBottomSheetThenCalled = true; |
| }); |
| |
| await tester.pumpAndSettle(); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| expect(showBottomSheetThenCalled, isFalse); |
| |
| // Swipe the bottom sheet to dismiss it. |
| await tester.drag(find.text('BottomSheet'), const Offset(0.0, 150.0)); |
| await tester.pumpAndSettle(); // Bottom sheet dismiss animation. |
| expect(showBottomSheetThenCalled, isTrue); |
| expect(find.text('BottomSheet'), findsNothing); |
| }); |
| |
| testWidgets('Modal BottomSheet builder should only be called once', (WidgetTester tester) async { |
| late BuildContext savedContext; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Builder( |
| builder: (BuildContext context) { |
| savedContext = context; |
| return Container(); |
| }, |
| ), |
| )); |
| |
| int numBuilderCalls = 0; |
| showModalBottomSheet<void>( |
| context: savedContext, |
| isDismissible: false, |
| enableDrag: true, |
| builder: (BuildContext context) { |
| numBuilderCalls++; |
| return const Text('BottomSheet'); |
| }, |
| ); |
| |
| await tester.pumpAndSettle(); |
| expect(numBuilderCalls, 1); |
| |
| // Swipe the bottom sheet to dismiss it. |
| await tester.drag(find.text('BottomSheet'), const Offset(0.0, 150.0)); |
| await tester.pumpAndSettle(); // Bottom sheet dismiss animation. |
| expect(numBuilderCalls, 1); |
| }); |
| |
| testWidgets('Verify that a downwards fling dismisses a persistent BottomSheet', (WidgetTester tester) async { |
| final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); |
| bool showBottomSheetThenCalled = false; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Scaffold( |
| key: scaffoldKey, |
| body: const Center(child: Text('body')), |
| ), |
| )); |
| |
| expect(showBottomSheetThenCalled, isFalse); |
| expect(find.text('BottomSheet'), findsNothing); |
| |
| scaffoldKey.currentState!.showBottomSheet<void>((BuildContext context) { |
| return Container( |
| margin: const EdgeInsets.all(40.0), |
| child: const Text('BottomSheet'), |
| ); |
| }).closed.whenComplete(() { |
| showBottomSheetThenCalled = true; |
| }); |
| |
| expect(showBottomSheetThenCalled, isFalse); |
| expect(find.text('BottomSheet'), findsNothing); |
| |
| await tester.pump(); // bottom sheet show animation starts |
| |
| expect(showBottomSheetThenCalled, isFalse); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| |
| await tester.pump(const Duration(seconds: 1)); // animation done |
| |
| expect(showBottomSheetThenCalled, isFalse); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| |
| // The fling below must be such that the velocity estimation examines an |
| // offset greater than the kTouchSlop. Too slow or too short a distance, and |
| // it won't trigger. Also, it must not be so much that it drags the bottom |
| // sheet off the screen, or we won't see it after we pump! |
| await tester.fling(find.text('BottomSheet'), const Offset(0.0, 50.0), 2000.0); |
| await tester.pump(); // drain the microtask queue (Future completion callback) |
| |
| expect(showBottomSheetThenCalled, isTrue); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| |
| await tester.pump(); // bottom sheet dismiss animation starts |
| |
| expect(showBottomSheetThenCalled, isTrue); |
| expect(find.text('BottomSheet'), findsOneWidget); |
| |
| await tester.pump(const Duration(seconds: 1)); // animation done |
| |
| expect(showBottomSheetThenCalled, isTrue); |
| expect(find.text('BottomSheet'), findsNothing); |
| }); |
| |
| testWidgets('Verify that dragging past the bottom dismisses a persistent BottomSheet', (WidgetTester tester) async { |
| // This is a regression test for https://github.com/flutter/flutter/issues/5528 |
| final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Scaffold( |
| key: scaffoldKey, |
| body: const Center(child: Text('body')), |
| ), |
| )); |
| |
| scaffoldKey.currentState!.showBottomSheet<void>((BuildContext context) { |
| return Container( |
| margin: const EdgeInsets.all(40.0), |
| child: const Text('BottomSheet'), |
| ); |
| }); |
| |
| await tester.pump(); // bottom sheet show animation starts |
| await tester.pump(const Duration(seconds: 1)); // animation done |
| expect(find.text('BottomSheet'), findsOneWidget); |
| |
| await tester.fling(find.text('BottomSheet'), const Offset(0.0, 400.0), 1000.0); |
| await tester.pump(); // drain the microtask queue (Future completion callback) |
| await tester.pump(); // bottom sheet dismiss animation starts |
| await tester.pump(const Duration(seconds: 1)); // animation done |
| |
| expect(find.text('BottomSheet'), findsNothing); |
| }); |
| |
| testWidgets('modal BottomSheet has no top MediaQuery', (WidgetTester tester) async { |
| late BuildContext outerContext; |
| late BuildContext innerContext; |
| |
| await tester.pumpWidget(Localizations( |
| locale: const Locale('en', 'US'), |
| delegates: const <LocalizationsDelegate<dynamic>>[ |
| DefaultWidgetsLocalizations.delegate, |
| DefaultMaterialLocalizations.delegate, |
| ], |
| child: Directionality( |
| textDirection: TextDirection.ltr, |
| child: MediaQuery( |
| data: const MediaQueryData( |
| padding: EdgeInsets.all(50.0), |
| size: Size(400.0, 600.0), |
| ), |
| child: Navigator( |
| onGenerateRoute: (_) { |
| return PageRouteBuilder<void>( |
| pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) { |
| outerContext = context; |
| return Container(); |
| }, |
| ); |
| }, |
| ), |
| ), |
| ), |
| )); |
| |
| showModalBottomSheet<void>( |
| context: outerContext, |
| builder: (BuildContext context) { |
| innerContext = context; |
| return Container(); |
| }, |
| ); |
| await tester.pump(); |
| await tester.pump(const Duration(seconds: 1)); |
| |
| expect( |
| MediaQuery.of(outerContext)!.padding, |
| const EdgeInsets.all(50.0), |
| ); |
| expect( |
| MediaQuery.of(innerContext)!.padding, |
| const EdgeInsets.only(left: 50.0, right: 50.0, bottom: 50.0), |
| ); |
| }); |
| |
| testWidgets('modal BottomSheet has semantics', (WidgetTester tester) async { |
| final SemanticsTester semantics = SemanticsTester(tester); |
| final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Scaffold( |
| key: scaffoldKey, |
| body: const Center(child: Text('body')), |
| ), |
| )); |
| |
| |
| showModalBottomSheet<void>(context: scaffoldKey.currentContext!, builder: (BuildContext context) { |
| return Container( |
| child: const Text('BottomSheet'), |
| ); |
| }); |
| |
| await tester.pump(); // bottom sheet show animation starts |
| await tester.pump(const Duration(seconds: 1)); // animation done |
| |
| expect(semantics, hasSemantics(TestSemantics.root( |
| children: <TestSemantics>[ |
| TestSemantics.rootChild( |
| children: <TestSemantics>[ |
| TestSemantics( |
| children: <TestSemantics>[ |
| TestSemantics( |
| label: 'Dialog', |
| textDirection: TextDirection.ltr, |
| flags: <SemanticsFlag>[ |
| SemanticsFlag.scopesRoute, |
| SemanticsFlag.namesRoute, |
| ], |
| children: <TestSemantics>[ |
| TestSemantics( |
| label: 'BottomSheet', |
| textDirection: TextDirection.ltr, |
| ), |
| ], |
| ), |
| ], |
| ), |
| TestSemantics(), |
| ], |
| ), |
| ], |
| ), ignoreTransform: true, ignoreRect: true, ignoreId: true)); |
| semantics.dispose(); |
| }); |
| |
| testWidgets('Verify that visual properties are passed through', (WidgetTester tester) async { |
| final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); |
| const Color color = Colors.pink; |
| const double elevation = 9.0; |
| final ShapeBorder shape = BeveledRectangleBorder(borderRadius: BorderRadius.circular(12)); |
| const Clip clipBehavior = Clip.antiAlias; |
| const Color barrierColor = Colors.red; |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Scaffold( |
| key: scaffoldKey, |
| body: const Center(child: Text('body')), |
| ), |
| )); |
| |
| showModalBottomSheet<void>( |
| context: scaffoldKey.currentContext!, |
| backgroundColor: color, |
| barrierColor: barrierColor, |
| elevation: elevation, |
| shape: shape, |
| clipBehavior: clipBehavior, |
| builder: (BuildContext context) { |
| return Container( |
| child: const Text('BottomSheet'), |
| ); |
| }, |
| ); |
| |
| await tester.pump(); |
| await tester.pump(const Duration(seconds: 1)); |
| |
| final BottomSheet bottomSheet = tester.widget(find.byType(BottomSheet)); |
| expect(bottomSheet.backgroundColor, color); |
| expect(bottomSheet.elevation, elevation); |
| expect(bottomSheet.shape, shape); |
| expect(bottomSheet.clipBehavior, clipBehavior); |
| |
| final ModalBarrier modalBarrier = tester.widget(find.byType(ModalBarrier).last); |
| expect(modalBarrier.color, barrierColor); |
| }); |
| |
| testWidgets('modal BottomSheet with scrollController has semantics', (WidgetTester tester) async { |
| final SemanticsTester semantics = SemanticsTester(tester); |
| final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Scaffold( |
| key: scaffoldKey, |
| body: const Center(child: Text('body')), |
| ), |
| )); |
| |
| |
| showModalBottomSheet<void>( |
| context: scaffoldKey.currentContext!, |
| builder: (BuildContext context) { |
| return DraggableScrollableSheet( |
| expand: false, |
| builder: (_, ScrollController controller) { |
| return SingleChildScrollView( |
| controller: controller, |
| child: Container( |
| child: const Text('BottomSheet'), |
| ), |
| ); |
| }, |
| ); |
| }, |
| ); |
| |
| await tester.pump(); // bottom sheet show animation starts |
| await tester.pump(const Duration(seconds: 1)); // animation done |
| |
| expect(semantics, hasSemantics(TestSemantics.root( |
| children: <TestSemantics>[ |
| TestSemantics.rootChild( |
| children: <TestSemantics>[ |
| TestSemantics( |
| children: <TestSemantics>[ |
| TestSemantics( |
| label: 'Dialog', |
| textDirection: TextDirection.ltr, |
| flags: <SemanticsFlag>[ |
| SemanticsFlag.scopesRoute, |
| SemanticsFlag.namesRoute, |
| ], |
| children: <TestSemantics>[ |
| TestSemantics( |
| flags: <SemanticsFlag>[SemanticsFlag.hasImplicitScrolling], |
| actions: <SemanticsAction>[SemanticsAction.scrollDown, SemanticsAction.scrollUp], |
| children: <TestSemantics>[ |
| TestSemantics( |
| label: 'BottomSheet', |
| textDirection: TextDirection.ltr, |
| ), |
| ], |
| ), |
| ], |
| ), |
| ], |
| ), |
| TestSemantics(), |
| ], |
| ), |
| ], |
| ), ignoreTransform: true, ignoreRect: true, ignoreId: true)); |
| semantics.dispose(); |
| }); |
| |
| testWidgets('showModalBottomSheet does not use root Navigator by default', (WidgetTester tester) async { |
| await tester.pumpWidget(MaterialApp( |
| home: Scaffold( |
| body: Navigator(onGenerateRoute: (RouteSettings settings) => MaterialPageRoute<void>(builder: (_) { |
| return const _TestPage(); |
| })), |
| bottomNavigationBar: BottomNavigationBar( |
| items: const <BottomNavigationBarItem>[ |
| BottomNavigationBarItem( |
| icon: Icon(Icons.ac_unit), |
| label: 'Item 1', |
| ), |
| BottomNavigationBarItem( |
| icon: Icon(Icons.style), |
| label: 'Item 2', |
| ), |
| ], |
| ), |
| ), |
| )); |
| |
| await tester.tap(find.text('Show bottom sheet')); |
| await tester.pumpAndSettle(); |
| |
| // Bottom sheet is displayed in correct position within the inner navigator |
| // and above the BottomNavigationBar. |
| expect(tester.getBottomLeft(find.byType(BottomSheet)).dy, 544.0); |
| }); |
| |
| testWidgets('showModalBottomSheet uses root Navigator when specified', (WidgetTester tester) async { |
| await tester.pumpWidget(MaterialApp( |
| home: Scaffold( |
| body: Navigator(onGenerateRoute: (RouteSettings settings) => MaterialPageRoute<void>(builder: (_) { |
| return const _TestPage(useRootNavigator: true); |
| })), |
| bottomNavigationBar: BottomNavigationBar( |
| items: const <BottomNavigationBarItem>[ |
| BottomNavigationBarItem( |
| icon: Icon(Icons.ac_unit), |
| label: 'Item 1', |
| ), |
| BottomNavigationBarItem( |
| icon: Icon(Icons.style), |
| label: 'Item 2', |
| ), |
| ], |
| ), |
| ), |
| )); |
| |
| await tester.tap(find.text('Show bottom sheet')); |
| await tester.pumpAndSettle(); |
| |
| // Bottom sheet is displayed in correct position above all content including |
| // the BottomNavigationBar. |
| expect(tester.getBottomLeft(find.byType(BottomSheet)).dy, 600.0); |
| }); |
| |
| testWidgets('Verify that route settings can be set in the showModalBottomSheet', |
| (WidgetTester tester) async { |
| final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); |
| const RouteSettings routeSettings = |
| RouteSettings(name: 'route_name', arguments: 'route_argument'); |
| |
| await tester.pumpWidget(MaterialApp( |
| home: Scaffold( |
| key: scaffoldKey, |
| body: const Center(child: Text('body')), |
| ), |
| )); |
| |
| late RouteSettings retrievedRouteSettings; |
| |
| showModalBottomSheet<void>( |
| context: scaffoldKey.currentContext!, |
| routeSettings: routeSettings, |
| builder: (BuildContext context) { |
| retrievedRouteSettings = ModalRoute.of(context)!.settings; |
| return Container( |
| child: const Text('BottomSheet'), |
| ); |
| }, |
| ); |
| |
| await tester.pump(); |
| await tester.pump(const Duration(seconds: 1)); |
| |
| expect(retrievedRouteSettings, routeSettings); |
| }); |
| } |
| |
| class _TestPage extends StatelessWidget { |
| const _TestPage({Key? key, this.useRootNavigator}) : super(key: key); |
| |
| final bool? useRootNavigator; |
| |
| @override |
| Widget build(BuildContext context) { |
| return Center( |
| child: TextButton( |
| child: const Text('Show bottom sheet'), |
| onPressed: () { |
| if (useRootNavigator != null) { |
| showModalBottomSheet<void>( |
| useRootNavigator: useRootNavigator!, |
| context: context, |
| builder: (_) => const Text('Modal bottom sheet'), |
| ); |
| } else { |
| showModalBottomSheet<void>( |
| context: context, |
| builder: (_) => const Text('Modal bottom sheet'), |
| ); |
| } |
| }, |
| ), |
| ); |
| } |
| } |