Make popup menu hardcoded padding configurable (#150506)

## Description

This PR exposed `PopupMenuButton.menuPadding` parameter to override the hardcoded value.

Credits to @Moluram for the original PR https://github.com/flutter/flutter/pull/81996.
And to @arafaysaleem for the update in https://github.com/flutter/flutter/pull/96657.

https://github.com/flutter/flutter/pull/96657 was reverted due to a Google testing failure. `PopupMenuButton` implementation has evolved since that time so maybe we will not hit this Google testing failure. And if we do, we will try to figure out what is going on.

## Related Issue

Fixes https://github.com/flutter/flutter/issues/143512.
Fixes https://github.com/flutter/flutter/issues/57110

## Tests

Adds 2 tests, updates several tests.
This commit is contained in:
Bruno Leroux 2024-06-20 21:18:21 +02:00 committed by GitHub
parent 80a65bd781
commit 4b0c8414fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 143 additions and 9 deletions

View File

@ -44,8 +44,13 @@ class _${blockName}DefaultsM3 extends PopupMenuThemeData {
@override @override
ShapeBorder? get shape => ${shape("md.comp.menu.container")}; ShapeBorder? get shape => ${shape("md.comp.menu.container")};
// TODO(bleroux): This is taken from https://m3.material.io/components/menus/specs
// Update this when the token is available.
@override
EdgeInsets? get menuPadding => const EdgeInsets.symmetric(vertical: 8.0);
// TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs // TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs
// Update this when the token is available. // Update this when the token is available.
static EdgeInsets menuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 12.0); static EdgeInsets menuItemPadding = const EdgeInsets.symmetric(horizontal: 12.0);
}'''; }''';
} }

View File

@ -39,7 +39,6 @@ const double _kMenuCloseIntervalEnd = 2.0 / 3.0;
const double _kMenuDividerHeight = 16.0; const double _kMenuDividerHeight = 16.0;
const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep; const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep;
const double _kMenuMinWidth = 2.0 * _kMenuWidthStep; const double _kMenuMinWidth = 2.0 * _kMenuWidthStep;
const double _kMenuVerticalPadding = 8.0;
const double _kMenuWidthStep = 56.0; const double _kMenuWidthStep = 56.0;
const double _kMenuScreenPadding = 8.0; const double _kMenuScreenPadding = 8.0;
@ -379,7 +378,7 @@ class PopupMenuItemState<T, W extends PopupMenuItem<T>> extends State<W> {
child: Container( child: Container(
alignment: AlignmentDirectional.centerStart, alignment: AlignmentDirectional.centerStart,
constraints: BoxConstraints(minHeight: widget.height), constraints: BoxConstraints(minHeight: widget.height),
padding: widget.padding ?? (theme.useMaterial3 ? _PopupMenuDefaultsM3.menuHorizontalPadding : _PopupMenuDefaultsM2.menuHorizontalPadding), padding: widget.padding ?? (theme.useMaterial3 ? _PopupMenuDefaultsM3.menuItemPadding : _PopupMenuDefaultsM2.menuItemPadding),
child: buildChild(), child: buildChild(),
), ),
); );
@ -610,7 +609,6 @@ class _PopupMenuState<T> extends State<_PopupMenu<T>> {
) { ) {
_setOpacities(); _setOpacities();
} }
} }
void _setOpacities() { void _setOpacities() {
@ -687,9 +685,7 @@ class _PopupMenuState<T> extends State<_PopupMenu<T>> {
explicitChildNodes: true, explicitChildNodes: true,
label: widget.semanticLabel, label: widget.semanticLabel,
child: SingleChildScrollView( child: SingleChildScrollView(
padding: const EdgeInsets.symmetric( padding: widget.route.menuPadding ?? popupMenuTheme.menuPadding ?? defaults.menuPadding,
vertical: _kMenuVerticalPadding,
),
child: ListBody(children: children), child: ListBody(children: children),
), ),
), ),
@ -853,6 +849,7 @@ class _PopupMenuRoute<T> extends PopupRoute<T> {
required this.barrierLabel, required this.barrierLabel,
this.semanticLabel, this.semanticLabel,
this.shape, this.shape,
this.menuPadding,
this.color, this.color,
required this.capturedThemes, required this.capturedThemes,
this.constraints, this.constraints,
@ -874,6 +871,7 @@ class _PopupMenuRoute<T> extends PopupRoute<T> {
final Color? shadowColor; final Color? shadowColor;
final String? semanticLabel; final String? semanticLabel;
final ShapeBorder? shape; final ShapeBorder? shape;
final EdgeInsetsGeometry? menuPadding;
final Color? color; final Color? color;
final CapturedThemes capturedThemes; final CapturedThemes capturedThemes;
final BoxConstraints? constraints; final BoxConstraints? constraints;
@ -1040,6 +1038,7 @@ Future<T?> showMenu<T>({
Color? surfaceTintColor, Color? surfaceTintColor,
String? semanticLabel, String? semanticLabel,
ShapeBorder? shape, ShapeBorder? shape,
EdgeInsetsGeometry? menuPadding,
Color? color, Color? color,
bool useRootNavigator = false, bool useRootNavigator = false,
BoxConstraints? constraints, BoxConstraints? constraints,
@ -1074,6 +1073,7 @@ Future<T?> showMenu<T>({
semanticLabel: semanticLabel, semanticLabel: semanticLabel,
barrierLabel: MaterialLocalizations.of(context).menuDismissLabel, barrierLabel: MaterialLocalizations.of(context).menuDismissLabel,
shape: shape, shape: shape,
menuPadding: menuPadding,
color: color, color: color,
capturedThemes: InheritedTheme.capture(from: context, to: navigator.context), capturedThemes: InheritedTheme.capture(from: context, to: navigator.context),
constraints: constraints, constraints: constraints,
@ -1194,6 +1194,7 @@ class PopupMenuButton<T> extends StatefulWidget {
this.shadowColor, this.shadowColor,
this.surfaceTintColor, this.surfaceTintColor,
this.padding = const EdgeInsets.all(8.0), this.padding = const EdgeInsets.all(8.0),
this.menuPadding,
this.child, this.child,
this.splashRadius, this.splashRadius,
this.icon, this.icon,
@ -1274,6 +1275,14 @@ class PopupMenuButton<T> extends StatefulWidget {
/// to set the padding to zero. /// to set the padding to zero.
final EdgeInsetsGeometry padding; final EdgeInsetsGeometry padding;
/// If provided, menu padding is used for empty space around the outside
/// of the popup menu.
///
/// If this property is null, then [PopupMenuThemeData.menuPadding] is used.
/// If [PopupMenuThemeData.menuPadding] is also null, then vertical padding
/// of 8 pixels is used.
final EdgeInsetsGeometry? menuPadding;
/// The splash radius. /// The splash radius.
/// ///
/// If null, default splash radius of [InkWell] or [IconButton] is used. /// If null, default splash radius of [InkWell] or [IconButton] is used.
@ -1475,6 +1484,7 @@ class PopupMenuButtonState<T> extends State<PopupMenuButton<T>> {
initialValue: widget.initialValue, initialValue: widget.initialValue,
position: position, position: position,
shape: widget.shape ?? popupMenuTheme.shape, shape: widget.shape ?? popupMenuTheme.shape,
menuPadding: widget.menuPadding ?? popupMenuTheme.menuPadding,
color: widget.color ?? popupMenuTheme.color, color: widget.color ?? popupMenuTheme.color,
constraints: widget.constraints, constraints: widget.constraints,
clipBehavior: widget.clipBehavior, clipBehavior: widget.clipBehavior,
@ -1571,7 +1581,10 @@ class _PopupMenuDefaultsM2 extends PopupMenuThemeData {
@override @override
TextStyle? get textStyle => _textTheme.titleMedium; TextStyle? get textStyle => _textTheme.titleMedium;
static EdgeInsets menuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 16.0); @override
EdgeInsets? get menuPadding => const EdgeInsets.symmetric(vertical: 8.0);
static EdgeInsets menuItemPadding = const EdgeInsets.symmetric(horizontal: 16.0);
} }
// BEGIN GENERATED TOKEN PROPERTIES - PopupMenu // BEGIN GENERATED TOKEN PROPERTIES - PopupMenu
@ -1613,8 +1626,13 @@ class _PopupMenuDefaultsM3 extends PopupMenuThemeData {
@override @override
ShapeBorder? get shape => const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))); ShapeBorder? get shape => const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0)));
// TODO(bleroux): This is taken from https://m3.material.io/components/menus/specs
// Update this when the token is available.
@override
EdgeInsets? get menuPadding => const EdgeInsets.symmetric(vertical: 8.0);
// TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs // TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs
// Update this when the token is available. // Update this when the token is available.
static EdgeInsets menuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 12.0); static EdgeInsets menuItemPadding = const EdgeInsets.symmetric(horizontal: 12.0);
} }
// END GENERATED TOKEN PROPERTIES - PopupMenu // END GENERATED TOKEN PROPERTIES - PopupMenu

View File

@ -47,6 +47,7 @@ class PopupMenuThemeData with Diagnosticable {
const PopupMenuThemeData({ const PopupMenuThemeData({
this.color, this.color,
this.shape, this.shape,
this.menuPadding,
this.elevation, this.elevation,
this.shadowColor, this.shadowColor,
this.surfaceTintColor, this.surfaceTintColor,
@ -65,6 +66,11 @@ class PopupMenuThemeData with Diagnosticable {
/// The shape of the popup menu. /// The shape of the popup menu.
final ShapeBorder? shape; final ShapeBorder? shape;
/// If specified, the padding of the popup menu.
///
/// If [PopupMenuButton.menuPadding] is provided, [menuPadding] is ignored.
final EdgeInsetsGeometry? menuPadding;
/// The elevation of the popup menu. /// The elevation of the popup menu.
final double? elevation; final double? elevation;
@ -108,6 +114,7 @@ class PopupMenuThemeData with Diagnosticable {
PopupMenuThemeData copyWith({ PopupMenuThemeData copyWith({
Color? color, Color? color,
ShapeBorder? shape, ShapeBorder? shape,
EdgeInsetsGeometry? menuPadding,
double? elevation, double? elevation,
Color? shadowColor, Color? shadowColor,
Color? surfaceTintColor, Color? surfaceTintColor,
@ -122,6 +129,7 @@ class PopupMenuThemeData with Diagnosticable {
return PopupMenuThemeData( return PopupMenuThemeData(
color: color ?? this.color, color: color ?? this.color,
shape: shape ?? this.shape, shape: shape ?? this.shape,
menuPadding: menuPadding ?? this.menuPadding,
elevation: elevation ?? this.elevation, elevation: elevation ?? this.elevation,
shadowColor: shadowColor ?? this.shadowColor, shadowColor: shadowColor ?? this.shadowColor,
surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor, surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor,
@ -147,6 +155,7 @@ class PopupMenuThemeData with Diagnosticable {
return PopupMenuThemeData( return PopupMenuThemeData(
color: Color.lerp(a?.color, b?.color, t), color: Color.lerp(a?.color, b?.color, t),
shape: ShapeBorder.lerp(a?.shape, b?.shape, t), shape: ShapeBorder.lerp(a?.shape, b?.shape, t),
menuPadding: EdgeInsetsGeometry.lerp(a?.menuPadding, b?.menuPadding, t),
elevation: lerpDouble(a?.elevation, b?.elevation, t), elevation: lerpDouble(a?.elevation, b?.elevation, t),
shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t), shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t),
surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t), surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t),
@ -164,6 +173,7 @@ class PopupMenuThemeData with Diagnosticable {
int get hashCode => Object.hash( int get hashCode => Object.hash(
color, color,
shape, shape,
menuPadding,
elevation, elevation,
shadowColor, shadowColor,
surfaceTintColor, surfaceTintColor,
@ -187,6 +197,7 @@ class PopupMenuThemeData with Diagnosticable {
return other is PopupMenuThemeData return other is PopupMenuThemeData
&& other.color == color && other.color == color
&& other.shape == shape && other.shape == shape
&& other.menuPadding == menuPadding
&& other.elevation == elevation && other.elevation == elevation
&& other.shadowColor == shadowColor && other.shadowColor == shadowColor
&& other.surfaceTintColor == surfaceTintColor && other.surfaceTintColor == surfaceTintColor
@ -204,6 +215,7 @@ class PopupMenuThemeData with Diagnosticable {
super.debugFillProperties(properties); super.debugFillProperties(properties);
properties.add(ColorProperty('color', color, defaultValue: null)); properties.add(ColorProperty('color', color, defaultValue: null));
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null)); properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('menuPadding', menuPadding, defaultValue: null));
properties.add(DoubleProperty('elevation', elevation, defaultValue: null)); properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null)); properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null));
properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null)); properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null));

View File

@ -1671,6 +1671,44 @@ void main() {
expect(tester.widget<Container>(find.widgetWithText(Container, 'Item 1')).padding, const EdgeInsets.symmetric(horizontal: 12.0)); expect(tester.widget<Container>(find.widgetWithText(Container, 'Item 1')).padding, const EdgeInsets.symmetric(horizontal: 12.0));
}); });
testWidgets('PopupMenu default padding', (WidgetTester tester) async {
final Key popupMenuButtonKey = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: PopupMenuButton<String>(
key: popupMenuButtonKey,
child: const Text('button'),
onSelected: (String result) { },
itemBuilder: (BuildContext context) {
return <PopupMenuEntry<String>>[
const PopupMenuItem<String>(
value: '0',
enabled: false,
child: Text('Item 0'),
),
const PopupMenuItem<String>(
value: '1',
child: Text('Item 1'),
),
];
},
),
),
),
),
);
// Show the menu.
await tester.tap(find.byKey(popupMenuButtonKey));
await tester.pump(const Duration(milliseconds: 300));
// Check popup menu padding.
final SingleChildScrollView popupMenu = tester.widget<SingleChildScrollView>(find.byType(SingleChildScrollView));
expect(popupMenu.padding, const EdgeInsets.symmetric(vertical: 8.0));
});
testWidgets('Material2 - PopupMenuItem default padding', (WidgetTester tester) async { testWidgets('Material2 - PopupMenuItem default padding', (WidgetTester tester) async {
final Key popupMenuButtonKey = UniqueKey(); final Key popupMenuButtonKey = UniqueKey();
await tester.pumpWidget( await tester.pumpWidget(
@ -1709,6 +1747,45 @@ void main() {
expect(tester.widget<Container>(find.widgetWithText(Container, 'Item 1')).padding, const EdgeInsets.symmetric(horizontal: 16.0)); expect(tester.widget<Container>(find.widgetWithText(Container, 'Item 1')).padding, const EdgeInsets.symmetric(horizontal: 16.0));
}); });
testWidgets('Material2 - PopupMenuItem default padding', (WidgetTester tester) async {
final Key popupMenuButtonKey = UniqueKey();
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(useMaterial3: false),
home: Scaffold(
body: Center(
child: PopupMenuButton<String>(
key: popupMenuButtonKey,
child: const Text('button'),
onSelected: (String result) { },
itemBuilder: (BuildContext context) {
return <PopupMenuEntry<String>>[
const PopupMenuItem<String>(
value: '0',
enabled: false,
child: Text('Item 0'),
),
const PopupMenuItem<String>(
value: '1',
child: Text('Item 1'),
),
];
},
),
),
),
),
);
// Show the menu.
await tester.tap(find.byKey(popupMenuButtonKey));
await tester.pump(const Duration(milliseconds: 300));
// Check popup menu padding.
final SingleChildScrollView popupMenu = tester.widget<SingleChildScrollView>(find.byType(SingleChildScrollView));
expect(popupMenu.padding, const EdgeInsets.symmetric(vertical: 8.0));
});
testWidgets('PopupMenuItem custom padding', (WidgetTester tester) async { testWidgets('PopupMenuItem custom padding', (WidgetTester tester) async {
final Key popupMenuButtonKey = UniqueKey(); final Key popupMenuButtonKey = UniqueKey();
final Type menuItemType = const PopupMenuItem<String>(child: Text('item')).runtimeType; final Type menuItemType = const PopupMenuItem<String>(child: Text('item')).runtimeType;

View File

@ -26,6 +26,7 @@ PopupMenuThemeData _popupMenuThemeM3() {
return PopupMenuThemeData( return PopupMenuThemeData(
color: Colors.orange, color: Colors.orange,
shape: const BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12))), shape: const BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12))),
menuPadding: const EdgeInsets.symmetric(vertical: 9.0),
elevation: 12.0, elevation: 12.0,
shadowColor: const Color(0xff00ff00), shadowColor: const Color(0xff00ff00),
surfaceTintColor: const Color(0xff00ff00), surfaceTintColor: const Color(0xff00ff00),
@ -62,6 +63,7 @@ void main() {
const PopupMenuThemeData popupMenuTheme = PopupMenuThemeData(); const PopupMenuThemeData popupMenuTheme = PopupMenuThemeData();
expect(popupMenuTheme.color, null); expect(popupMenuTheme.color, null);
expect(popupMenuTheme.shape, null); expect(popupMenuTheme.shape, null);
expect(popupMenuTheme.menuPadding, null);
expect(popupMenuTheme.elevation, null); expect(popupMenuTheme.elevation, null);
expect(popupMenuTheme.shadowColor, null); expect(popupMenuTheme.shadowColor, null);
expect(popupMenuTheme.surfaceTintColor, null); expect(popupMenuTheme.surfaceTintColor, null);
@ -88,6 +90,7 @@ void main() {
PopupMenuThemeData( PopupMenuThemeData(
color: const Color(0xfffffff1), color: const Color(0xfffffff1),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0))), shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0))),
menuPadding: const EdgeInsets.symmetric(vertical: 12.0),
elevation: 2.0, elevation: 2.0,
shadowColor: const Color(0xfffffff2), shadowColor: const Color(0xfffffff2),
surfaceTintColor: const Color(0xfffffff3), surfaceTintColor: const Color(0xfffffff3),
@ -113,6 +116,7 @@ void main() {
expect(description, <String>[ expect(description, <String>[
'color: Color(0xfffffff1)', 'color: Color(0xfffffff1)',
'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))', 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))',
'menuPadding: EdgeInsets(0.0, 12.0, 0.0, 12.0)',
'elevation: 2.0', 'elevation: 2.0',
'shadowColor: Color(0xfffffff2)', 'shadowColor: Color(0xfffffff2)',
'surfaceTintColor: Color(0xfffffff3)', 'surfaceTintColor: Color(0xfffffff3)',
@ -244,6 +248,10 @@ void main() {
// Test checked CheckedPopupMenuItem label. // Test checked CheckedPopupMenuItem label.
listTile = tester.widget<ListTile>(find.byType(ListTile).last); listTile = tester.widget<ListTile>(find.byType(ListTile).last);
expect(listTile.titleTextStyle?.color, theme.colorScheme.onSurface); expect(listTile.titleTextStyle?.color, theme.colorScheme.onSurface);
// Check popup menu padding.
final SingleChildScrollView popupMenu = tester.widget<SingleChildScrollView>(find.byType(SingleChildScrollView));
expect(popupMenu.padding, const EdgeInsets.symmetric(vertical: 8.0));
}); });
testWidgets('Popup menu uses values from PopupMenuThemeData', (WidgetTester tester) async { testWidgets('Popup menu uses values from PopupMenuThemeData', (WidgetTester tester) async {
@ -360,6 +368,10 @@ void main() {
// Test checked CheckedPopupMenuItem label. // Test checked CheckedPopupMenuItem label.
listTile = tester.widget<ListTile>(find.byType(ListTile).last); listTile = tester.widget<ListTile>(find.byType(ListTile).last);
expect(listTile.titleTextStyle, popupMenuTheme.labelTextStyle?.resolve(enabled)); expect(listTile.titleTextStyle, popupMenuTheme.labelTextStyle?.resolve(enabled));
// Check popup menu padding.
final SingleChildScrollView popupMenu = tester.widget<SingleChildScrollView>(find.byType(SingleChildScrollView));
expect(popupMenu.padding, popupMenuTheme.menuPadding);
}); });
testWidgets('Popup menu widget properties take priority over theme', (WidgetTester tester) async { testWidgets('Popup menu widget properties take priority over theme', (WidgetTester tester) async {
@ -374,6 +386,7 @@ void main() {
const ShapeBorder shape = RoundedRectangleBorder( const ShapeBorder shape = RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(9.0)), borderRadius: BorderRadius.all(Radius.circular(9.0)),
); );
const EdgeInsets menuPadding = EdgeInsets.zero;
const double elevation = 7.0; const double elevation = 7.0;
const TextStyle textStyle = TextStyle(color: Color(0xfff14fff), fontSize: 19.0); const TextStyle textStyle = TextStyle(color: Color(0xfff14fff), fontSize: 19.0);
const MouseCursor cursor = SystemMouseCursors.forbidden; const MouseCursor cursor = SystemMouseCursors.forbidden;
@ -393,6 +406,7 @@ void main() {
surfaceTintColor: surfaceTintColor, surfaceTintColor: surfaceTintColor,
color: color, color: color,
shape: shape, shape: shape,
menuPadding: menuPadding,
iconColor: iconColor, iconColor: iconColor,
iconSize: iconSize, iconSize: iconSize,
itemBuilder: (BuildContext context) { itemBuilder: (BuildContext context) {
@ -460,6 +474,10 @@ void main() {
// Test CheckedPopupMenuItem label. // Test CheckedPopupMenuItem label.
final ListTile listTile = tester.widget<ListTile>(find.byType(ListTile).first); final ListTile listTile = tester.widget<ListTile>(find.byType(ListTile).first);
expect(listTile.titleTextStyle, textStyle); expect(listTile.titleTextStyle, textStyle);
// Check popup menu padding.
final SingleChildScrollView popupMenu = tester.widget<SingleChildScrollView>(find.byType(SingleChildScrollView));
expect(popupMenu.padding, EdgeInsets.zero);
}); });
group('Material 2', () { group('Material 2', () {
@ -564,6 +582,10 @@ void main() {
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
SystemMouseCursors.click, SystemMouseCursors.click,
); );
// Check popup menu padding.
final SingleChildScrollView popupMenu = tester.widget<SingleChildScrollView>(find.byType(SingleChildScrollView));
expect(popupMenu.padding, const EdgeInsets.symmetric(vertical: 8.0));
}); });
testWidgets('Popup menu uses values from PopupMenuThemeData', (WidgetTester tester) async { testWidgets('Popup menu uses values from PopupMenuThemeData', (WidgetTester tester) async {