Unverified Commit 5064f782 authored by Kostia Sokolovskyi's avatar Kostia Sokolovskyi Committed by GitHub

Cover more test/material tests with leak tracking. (#136093)

parent 83134ac7
......@@ -876,7 +876,7 @@ void main() {
expect(tester.getSize(find.byKey(keyA)), equals(const Size(20.0, 20.0)));
});
testWidgets('Chip padding - LTR', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Chip padding - LTR', (WidgetTester tester) async {
final GlobalKey keyA = GlobalKey();
final GlobalKey keyB = GlobalKey();
......@@ -915,7 +915,7 @@ void main() {
expect(tester.getBottomRight(find.byType(Icon)), const Offset(457.0, 309.0));
});
testWidgets('Chip padding - RTL', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Chip padding - RTL', (WidgetTester tester) async {
final GlobalKey keyA = GlobalKey();
final GlobalKey keyB = GlobalKey();
......@@ -1849,7 +1849,7 @@ void main() {
expect(tester.getSize(find.byKey(key2)), const Size(80.0, 32.0));
});
testWidgets('Chip uses the right theme colors for the right components', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Chip uses the right theme colors for the right components', (WidgetTester tester) async {
final ThemeData themeData = ThemeData(
platform: TargetPlatform.android,
primarySwatch: Colors.blue,
......@@ -2596,7 +2596,7 @@ void main() {
checkChipMaterialClipBehavior(tester, Clip.antiAlias);
});
testWidgets('selected chip and avatar draw darkened layer within avatar circle', (WidgetTester tester) async {
testWidgetsWithLeakTracking('selected chip and avatar draw darkened layer within avatar circle', (WidgetTester tester) async {
await tester.pumpWidget(
wrapForChip(
useMaterial3: false,
......@@ -2639,8 +2639,9 @@ void main() {
expect(find.byType(InkWell), findsOneWidget);
});
testWidgets('Chip uses stateful color for text color in different states', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Chip uses stateful color for text color in different states', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
const Color pressedColor = Color(0x00000001);
const Color hoverColor = Color(0x00000002);
......@@ -2727,8 +2728,9 @@ void main() {
expect(textColor(), disabledColor);
});
testWidgets('Chip uses stateful border side color in different states', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Chip uses stateful border side color in different states', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
const Color pressedColor = Color(0x00000001);
const Color hoverColor = Color(0x00000002);
......@@ -2807,8 +2809,9 @@ void main() {
expect(find.byType(RawChip), paints..rrect()..rrect(color: disabledColor));
});
testWidgets('Chip uses stateful border side color from resolveWith', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Chip uses stateful border side color from resolveWith', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
const Color pressedColor = Color(0x00000001);
const Color hoverColor = Color(0x00000002);
......@@ -2888,8 +2891,9 @@ void main() {
});
testWidgets('Chip uses stateful nullable border side color from resolveWith', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Chip uses stateful nullable border side color from resolveWith', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
const Color pressedColor = Color(0x00000001);
const Color hoverColor = Color(0x00000002);
......@@ -2977,8 +2981,9 @@ void main() {
expect(find.byType(RawChip), paints..rrect()..rrect(color: disabledColor));
});
testWidgets('Chip uses stateful shape in different states', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Chip uses stateful shape in different states', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode();
addTearDown(focusNode.dispose);
OutlinedBorder? getShape(Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
......@@ -3320,8 +3325,9 @@ void main() {
expect(decoration.shape, shape);
});
testWidgets('Chip highlight color is drawn on top of the backgroundColor', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Chip highlight color is drawn on top of the backgroundColor', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(debugLabel: 'RawChip');
addTearDown(focusNode.dispose);
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
const Color backgroundColor = Color(0xff00ff00);
......@@ -3443,7 +3449,7 @@ void main() {
expect(getMaterialBox(tester), paints..rrect(color: selectedColor));
});
testWidgets('Delete button tap target area does not include label', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Delete button tap target area does not include label', (WidgetTester tester) async {
bool calledDelete = false;
await tester.pumpWidget(
wrapForChip(
......@@ -3486,7 +3492,7 @@ void main() {
});
// This is a regression test for https://github.com/flutter/flutter/pull/133615.
testWidgets('Material3 - Custom shape without provided side uses default side', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Material3 - Custom shape without provided side uses default side', (WidgetTester tester) async {
final ThemeData theme = ThemeData(useMaterial3: true);
await tester.pumpWidget(
MaterialApp(
......@@ -3510,7 +3516,7 @@ void main() {
);
});
testWidgets("Material3 - RawChip.shape's side is used when provided", (WidgetTester tester) async {
testWidgetsWithLeakTracking("Material3 - RawChip.shape's side is used when provided", (WidgetTester tester) async {
Widget buildChip({ OutlinedBorder? shape, BorderSide? side }) {
return MaterialApp(
theme: ThemeData(useMaterial3: true),
......@@ -3569,7 +3575,7 @@ void main() {
// support is deprecated and the APIs are removed, these tests
// can be deleted.
testWidgets('M2 Chip defaults', (WidgetTester tester) async {
testWidgetsWithLeakTracking('M2 Chip defaults', (WidgetTester tester) async {
late TextTheme textTheme;
Widget buildFrame(Brightness brightness) {
......@@ -3646,7 +3652,7 @@ void main() {
expect(labelStyle.wordSpacing, textTheme.bodyLarge?.wordSpacing);
});
testWidgets('Chip uses the right theme colors for the right components', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Chip uses the right theme colors for the right components', (WidgetTester tester) async {
final ThemeData themeData = ThemeData(
platform: TargetPlatform.android,
primarySwatch: Colors.blue,
......
......@@ -929,7 +929,7 @@ void main() {
);
});
testWidgets("Material3 - RawChip.shape's side is used when provided", (WidgetTester tester) async {
testWidgetsWithLeakTracking("Material3 - RawChip.shape's side is used when provided", (WidgetTester tester) async {
Widget buildChip({ OutlinedBorder? shape, BorderSide? side }) {
return MaterialApp(
theme: ThemeData(
......
......@@ -698,7 +698,7 @@ void main() {
expect(find.text('disabled'), findsOneWidget);
});
testWidgets(
testWidgetsWithLeakTracking(
'DropdownButtonFormField - hint displays when the items list is '
'empty, items is null, and disabledHint is null',
(WidgetTester tester) async {
......@@ -1232,7 +1232,7 @@ void main() {
expect(inkWell.borderRadius, errorBorderRadius);
});
testWidgets('DropdownButtonFormField onChanged is called when the form is reset', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButtonFormField onChanged is called when the form is reset', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/123009.
final GlobalKey<FormFieldState<String>> stateKey = GlobalKey<FormFieldState<String>>();
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
......
......@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() {
const String longText = 'one two three four five six seven eight nine ten eleven twelve';
......@@ -34,7 +35,7 @@ void main() {
);
}
testWidgets('DropdownMenu defaults', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownMenu defaults', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(buildTest(themeData, menuChildren));
......@@ -82,7 +83,7 @@ void main() {
expect(material.textStyle?.height, 1.43);
});
testWidgets('DropdownMenu can be disabled', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownMenu can be disabled', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(
MaterialApp(
......@@ -115,7 +116,7 @@ void main() {
expect(updatedMenuMaterial, findsNothing);
});
testWidgets('Material2 - The width of the text field should always be the same as the menu view',
testWidgetsWithLeakTracking('Material2 - The width of the text field should always be the same as the menu view',
(WidgetTester tester) async {
final ThemeData themeData = ThemeData(useMaterial3: false);
......@@ -165,7 +166,7 @@ void main() {
expect(updatedMenuWidth, 200.0);
});
testWidgets('Material3 - The width of the text field should always be the same as the menu view',
testWidgetsWithLeakTracking('Material3 - The width of the text field should always be the same as the menu view',
(WidgetTester tester) async {
final ThemeData themeData = ThemeData(useMaterial3: true);
await tester.pumpWidget(
......@@ -214,7 +215,7 @@ void main() {
expect(updatedMenuWidth, 200.0);
});
testWidgets('The width property can customize the width of the dropdown menu', (WidgetTester tester) async {
testWidgetsWithLeakTracking('The width property can customize the width of the dropdown menu', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
final List<DropdownMenuEntry<ShortMenu>> shortMenuItems = <DropdownMenuEntry<ShortMenu>>[];
......@@ -248,7 +249,7 @@ void main() {
expect(buttonSize.width, customSmallWidth);
});
testWidgets('The width property update test', (WidgetTester tester) async {
testWidgetsWithLeakTracking('The width property update test', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/120567
final ThemeData themeData = ThemeData();
final List<DropdownMenuEntry<ShortMenu>> shortMenuItems = <DropdownMenuEntry<ShortMenu>>[];
......@@ -270,7 +271,7 @@ void main() {
expect(box.size.width, customWidth);
});
testWidgets('The width of MenuAnchor respects MenuAnchor.expandedInsets', (WidgetTester tester) async {
testWidgetsWithLeakTracking('The width of MenuAnchor respects MenuAnchor.expandedInsets', (WidgetTester tester) async {
const double parentWidth = 500.0;
final List<DropdownMenuEntry<ShortMenu>> shortMenuItems = <DropdownMenuEntry<ShortMenu>>[];
for (final ShortMenu value in ShortMenu.values) {
......@@ -334,7 +335,7 @@ void main() {
expect(buttonSize.width, parentWidth - 35.0 - 20.0);
});
testWidgets('Material2 - The menuHeight property can be used to show a shorter scrollable menu list instead of the complete list',
testWidgetsWithLeakTracking('Material2 - The menuHeight property can be used to show a shorter scrollable menu list instead of the complete list',
(WidgetTester tester) async {
final ThemeData themeData = ThemeData(useMaterial3: false);
await tester.pumpWidget(buildTest(themeData, menuChildren));
......@@ -375,7 +376,7 @@ void main() {
expect(updatedMenuSize, const Size(180.0, 100.0));
});
testWidgets('Material3 - The menuHeight property can be used to show a shorter scrollable menu list instead of the complete list',
testWidgetsWithLeakTracking('Material3 - The menuHeight property can be used to show a shorter scrollable menu list instead of the complete list',
(WidgetTester tester) async {
final ThemeData themeData = ThemeData(useMaterial3: true);
await tester.pumpWidget(buildTest(themeData, menuChildren));
......@@ -418,7 +419,7 @@ void main() {
expect(updatedMenuSize.height, equals(100.0));
});
testWidgets('The text in the menu button should be aligned with the text of '
testWidgetsWithLeakTracking('The text in the menu button should be aligned with the text of '
'the text field - LTR', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
// Default text field (without leading icon).
......@@ -479,7 +480,7 @@ void main() {
expect(updatedLabelTopLeft1.dx, equals(largeIconWidth));
});
testWidgets('The text in the menu button should be aligned with the text of '
testWidgetsWithLeakTracking('The text in the menu button should be aligned with the text of '
'the text field - RTL', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
// Default text field (without leading icon).
......@@ -571,7 +572,7 @@ void main() {
expect(updatedLabelTopRight1.dx, equals(updatedDropdownMenuTopRight.dx - largeIconWidth));
});
testWidgets('DropdownMenu has default trailing icon button', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownMenu has default trailing icon button', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(buildTest(themeData, menuChildren));
await tester.pump();
......@@ -589,7 +590,7 @@ void main() {
expect(menuMaterial, findsOneWidget);
});
testWidgets('Leading IconButton status test', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Leading IconButton status test', (WidgetTester tester) async {
final ThemeData themeData = ThemeData(useMaterial3: true);
await tester.pumpWidget(buildTest(themeData, menuChildren, width: 100.0, menuHeight: 100.0));
await tester.pump();
......@@ -617,7 +618,7 @@ void main() {
expect(iconButton, findsOneWidget);
});
testWidgets('Do not crash when resize window during menu opening', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Do not crash when resize window during menu opening', (WidgetTester tester) async {
addTearDown(tester.view.reset);
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
......@@ -653,7 +654,7 @@ void main() {
// Go without throw.
});
testWidgets('DropdownMenu can customize trailing icon button', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownMenu can customize trailing icon button', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
theme: themeData,
......@@ -679,7 +680,7 @@ void main() {
expect(menuMaterial, findsOneWidget);
});
testWidgets('Down key can highlight the menu item on desktop platforms', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Down key can highlight the menu item on desktop platforms', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
theme: themeData,
......@@ -721,7 +722,7 @@ void main() {
expect(item0material.color, Colors.transparent); // the previous item should not be highlighted.
}, variant: TargetPlatformVariant.desktop());
testWidgets('Up key can highlight the menu item on desktop platforms', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Up key can highlight the menu item on desktop platforms', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
theme: themeData,
......@@ -763,7 +764,7 @@ void main() {
expect(item5material.color, Colors.transparent); // the previous item should not be highlighted.
}, variant: TargetPlatformVariant.desktop());
testWidgets('The text input should match the label of the menu item '
testWidgetsWithLeakTracking('The text input should match the label of the menu item '
'while pressing down key on desktop platforms', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
......@@ -794,7 +795,7 @@ void main() {
expect(find.widgetWithText(TextField, 'Item 2'), findsOneWidget);
}, variant: TargetPlatformVariant.desktop());
testWidgets('The text input should match the label of the menu item '
testWidgetsWithLeakTracking('The text input should match the label of the menu item '
'while pressing up key on desktop platforms', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
......@@ -825,7 +826,7 @@ void main() {
expect(find.widgetWithText(TextField, 'Item 3'), findsOneWidget);
}, variant: TargetPlatformVariant.desktop());
testWidgets('Disabled button will be skipped while pressing up/down key on desktop platforms', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Disabled button will be skipped while pressing up/down key on desktop platforms', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
final List<DropdownMenuEntry<TestMenu>> menuWithDisabledItems = <DropdownMenuEntry<TestMenu>>[
const DropdownMenuEntry<TestMenu>(value: TestMenu.mainMenu0, label: 'Item 0'),
......@@ -869,7 +870,7 @@ void main() {
expect(item3Material.color, themeData.colorScheme.onSurface.withOpacity(0.12));
}, variant: TargetPlatformVariant.desktop());
testWidgets('Searching is enabled by default on mobile platforms if initialSelection is non null', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Searching is enabled by default on mobile platforms if initialSelection is non null', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
theme: themeData,
......@@ -892,7 +893,7 @@ void main() {
expect(itemMaterial.color, themeData.colorScheme.onSurface.withOpacity(0.12)); // Menu 1 button is highlighted.
}, variant: TargetPlatformVariant.mobile());
testWidgets('Searching is enabled by default on desktop platform', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Searching is enabled by default on desktop platform', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
theme: themeData,
......@@ -916,7 +917,7 @@ void main() {
expect(itemMaterial.color, themeData.colorScheme.onSurface.withOpacity(0.12)); // Menu 1 button is highlighted.
}, variant: TargetPlatformVariant.desktop());
testWidgets('Highlight can move up/down starting from the searching result on desktop platforms', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Highlight can move up/down starting from the searching result on desktop platforms', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
theme: themeData,
......@@ -962,7 +963,7 @@ void main() {
expect(item5Material.color, themeData.colorScheme.onSurface.withOpacity(0.12));
}, variant: TargetPlatformVariant.desktop());
testWidgets('Filtering is disabled by default', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Filtering is disabled by default', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
theme: themeData,
......@@ -986,7 +987,7 @@ void main() {
}
});
testWidgets('Enable filtering', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Enable filtering', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
theme: themeData,
......@@ -1017,9 +1018,11 @@ void main() {
}
});
testWidgets('The controller can access the value in the input field', (WidgetTester tester) async {
testWidgetsWithLeakTracking('The controller can access the value in the input field', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
final TextEditingController controller = TextEditingController();
addTearDown(controller.dispose);
await tester.pumpWidget(MaterialApp(
theme: themeData,
home: StatefulBuilder(
......@@ -1049,9 +1052,11 @@ void main() {
expect(controller.text, 'New Item');
});
testWidgets('The menu should be closed after text editing is complete', (WidgetTester tester) async {
testWidgetsWithLeakTracking('The menu should be closed after text editing is complete', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
final TextEditingController controller = TextEditingController();
addTearDown(controller.dispose);
await tester.pumpWidget(MaterialApp(
theme: themeData,
home: Scaffold(
......@@ -1077,7 +1082,7 @@ void main() {
expect(menuAnchor.controller!.isOpen, false);
});
testWidgets('The onSelected gets called only when a selection is made', (WidgetTester tester) async {
testWidgetsWithLeakTracking('The onSelected gets called only when a selection is made', (WidgetTester tester) async {
int selectionCount = 0;
final ThemeData themeData = ThemeData();
......@@ -1088,6 +1093,8 @@ void main() {
const DropdownMenuEntry<TestMenu>(value: TestMenu.mainMenu0, label: 'Item 3'),
];
final TextEditingController controller = TextEditingController();
addTearDown(controller.dispose);
await tester.pumpWidget(MaterialApp(
theme: themeData,
home: StatefulBuilder(
......@@ -1174,9 +1181,11 @@ void main() {
}, variant: TargetPlatformVariant.all());
testWidgets('The selectedValue gives an initial text and highlights the according item', (WidgetTester tester) async {
testWidgetsWithLeakTracking('The selectedValue gives an initial text and highlights the according item', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
final TextEditingController controller = TextEditingController();
addTearDown(controller.dispose);
await tester.pumpWidget(MaterialApp(
theme: themeData,
home: StatefulBuilder(
......@@ -1208,7 +1217,7 @@ void main() {
expect(itemMaterial.color, themeData.colorScheme.onSurface.withOpacity(0.12));
});
testWidgets('The default text input field should not be focused on mobile platforms '
testWidgetsWithLeakTracking('The default text input field should not be focused on mobile platforms '
'when it is tapped', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
......@@ -1234,7 +1243,7 @@ void main() {
expect(result.canRequestFocus, false);
}, variant: TargetPlatformVariant.mobile());
testWidgets('The text input field should be focused on desktop platforms '
testWidgetsWithLeakTracking('The text input field should be focused on desktop platforms '
'when it is tapped', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
......@@ -1259,7 +1268,7 @@ void main() {
expect(result.canRequestFocus, true);
}, variant: TargetPlatformVariant.desktop());
testWidgets('If requestFocusOnTap is true, the text input field can request focus, '
testWidgetsWithLeakTracking('If requestFocusOnTap is true, the text input field can request focus, '
'otherwise it cannot request focus', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
......@@ -1309,7 +1318,7 @@ void main() {
expect(find.widgetWithText(TextField, 'Item 0'), findsOneWidget);
}, variant: TargetPlatformVariant.all());
testWidgets('If requestFocusOnTap is false, the mouse cursor should be clickable when hovered', (WidgetTester tester) async {
testWidgetsWithLeakTracking('If requestFocusOnTap is false, the mouse cursor should be clickable when hovered', (WidgetTester tester) async {
Widget buildDropdownMenu() => MaterialApp(
home: Scaffold(
body: Column(
......@@ -1335,7 +1344,7 @@ void main() {
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click);
});
testWidgets('The menu has the same width as the input field in ListView', (WidgetTester tester) async {
testWidgetsWithLeakTracking('The menu has the same width as the input field in ListView', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/123631
await tester.pumpWidget(MaterialApp(
home: Scaffold(
......@@ -1387,11 +1396,12 @@ void main() {
expect(menu1.width, 200);
});
testWidgets('Semantics does not include hint when input is not empty', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Semantics does not include hint when input is not empty', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
const String hintText = 'I am hintText';
TestMenu? selectedValue;
final TextEditingController controller = TextEditingController();
addTearDown(controller.dispose);
await tester.pumpWidget(
StatefulBuilder(
......@@ -1430,7 +1440,7 @@ void main() {
expect(node.value, 'Item 3');
});
testWidgets('helperText is not visible when errorText is not null', (WidgetTester tester) async {
testWidgetsWithLeakTracking('helperText is not visible when errorText is not null', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
const String helperText = 'I am helperText';
const String errorText = 'I am errorText';
......@@ -1460,7 +1470,7 @@ void main() {
expect(find.text(errorText), findsOneWidget);
});
testWidgets('DropdownMenu can respect helperText when helperText is not null', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownMenu can respect helperText when helperText is not null', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
const String helperText = 'I am helperText';
......@@ -1482,7 +1492,7 @@ void main() {
expect(find.text(helperText), findsOneWidget);
});
testWidgets('DropdownMenu can respect errorText when errorText is not null', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownMenu can respect errorText when errorText is not null', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
const String errorText = 'I am errorText';
......@@ -1504,7 +1514,7 @@ void main() {
expect(find.text(errorText), findsOneWidget);
});
testWidgets('Can scroll to the highlighted item', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Can scroll to the highlighted item', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: DropdownMenu<TestMenu>(
......@@ -1527,7 +1537,7 @@ void main() {
});
// This is a regression test for https://github.com/flutter/flutter/issues/131676.
testWidgets('Material3 - DropdownMenu uses correct text styles', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Material3 - DropdownMenu uses correct text styles', (WidgetTester tester) async {
const TextStyle inputTextThemeStyle = TextStyle(
fontSize: 18.5,
fontStyle: FontStyle.italic,
......@@ -1573,9 +1583,10 @@ void main() {
expect(material.textStyle?.decoration, menuItemTextThemeStyle.decoration);
});
testWidgets('DropdownMenuEntries do not overflow when width is specified', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownMenuEntries do not overflow when width is specified', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/126882
final TextEditingController controller = TextEditingController();
addTearDown(controller.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -1619,9 +1630,10 @@ void main() {
expect(controller.text, 'Item 0 $longText');
});
testWidgets('DropdownMenuEntry.labelWidget is Text that specifies maxLines 1 or 2', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownMenuEntry.labelWidget is Text that specifies maxLines 1 or 2', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/126882
final TextEditingController controller = TextEditingController();
addTearDown(controller.dispose);
Widget buildFrame({ required int maxLines }) {
return MaterialApp(
......@@ -1682,7 +1694,7 @@ void main() {
});
// Regression test for https://github.com/flutter/flutter/issues/131350.
testWidgets('DropdownMenuEntry.leadingIcon default layout', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownMenuEntry.leadingIcon default layout', (WidgetTester tester) async {
// The DropdownMenu should not get extra padding in DropdownMenuEntry items
// when both text field and DropdownMenuEntry have leading icons.
await tester.pumpWidget(const MaterialApp(
......
......@@ -22,6 +22,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart';
......@@ -339,7 +340,7 @@ Future<void> checkDropdownColor(WidgetTester tester, {Color? color, bool isFormF
}
void main() {
testWidgets('Default dropdown golden', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Default dropdown golden', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
Widget build() => buildFrame(buttonKey: buttonKey, onChanged: onChanged, useMaterial3: false);
await tester.pumpWidget(build());
......@@ -351,7 +352,7 @@ void main() {
);
});
testWidgets('Expanded dropdown golden', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Expanded dropdown golden', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
Widget build() => buildFrame(buttonKey: buttonKey, isExpanded: true, onChanged: onChanged, useMaterial3: false);
await tester.pumpWidget(build());
......@@ -363,7 +364,7 @@ void main() {
);
});
testWidgets('Dropdown button control test', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown button control test', (WidgetTester tester) async {
String? value = 'one';
void didChangeValue(String? newValue) {
value = newValue;
......@@ -402,7 +403,7 @@ void main() {
expect(value, equals('two'));
});
testWidgets('Dropdown button with no app', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown button with no app', (WidgetTester tester) async {
String? value = 'one';
void didChangeValue(String? newValue) {
value = newValue;
......@@ -461,7 +462,7 @@ void main() {
expect(value, equals('two'));
});
testWidgets('DropdownButton does not allow duplicate item values', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton does not allow duplicate item values', (WidgetTester tester) async {
final List<DropdownMenuItem<String>> itemsWithDuplicateValues = <String>['a', 'b', 'c', 'c']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
......@@ -490,7 +491,7 @@ void main() {
);
});
testWidgets('DropdownButton value should only appear in one menu item', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton value should only appear in one menu item', (WidgetTester tester) async {
final List<DropdownMenuItem<String>> itemsWithDuplicateValues = <String>['a', 'b', 'c', 'd']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
......@@ -519,7 +520,7 @@ void main() {
);
});
testWidgets('Dropdown form field uses form field state', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown form field uses form field state', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
String? value;
......@@ -576,7 +577,7 @@ void main() {
expect(value, equals('three'));
});
testWidgets('Dropdown in ListView', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown in ListView', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/12053
// Positions a DropdownButton at the left and right edges of the screen,
// forcing it to be sized down to the viewport width
......@@ -611,7 +612,7 @@ void main() {
expect(itemBoxes[1].size.width, equals(800.0 - 16.0 * 2));
});
testWidgets('Dropdown menu can position correctly inside a nested navigator', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown menu can position correctly inside a nested navigator', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/66870
await tester.pumpWidget(
MaterialApp(
......@@ -657,7 +658,7 @@ void main() {
expect(secondItem.localToGlobal(Offset.zero).dy, equals(176.0));
});
testWidgets('Dropdown screen edges', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown screen edges', (WidgetTester tester) async {
int? value = 4;
final List<DropdownMenuItem<int>> items = <DropdownMenuItem<int>>[
for (int i = 0; i < 20; ++i) DropdownMenuItem<int>(value: i, child: Text('$i')),
......@@ -701,7 +702,7 @@ void main() {
});
for (final TextDirection textDirection in TextDirection.values) {
testWidgets('Dropdown button aligns selected menu item ($textDirection)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown button aligns selected menu item ($textDirection)', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
Widget build() => buildFrame(buttonKey: buttonKey, textDirection: textDirection, onChanged: onChanged, useMaterial3: false);
......@@ -745,7 +746,7 @@ void main() {
});
}
testWidgets('Arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
Widget build() => buildFrame(buttonKey: buttonKey, isExpanded: true, onChanged: onChanged);
......@@ -764,7 +765,7 @@ void main() {
);
});
testWidgets('Dropdown button icon will accept widgets as icons', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown button icon will accept widgets as icons', (WidgetTester tester) async {
final Widget customWidget = Container(
decoration: ShapeDecoration(
shape: CircleBorder(
......@@ -793,7 +794,7 @@ void main() {
expect(find.byIcon(Icons.arrow_drop_down), findsNothing);
});
testWidgets('Dropdown button icon should have default size and colors when not defined', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown button icon should have default size and colors when not defined', (WidgetTester tester) async {
final Key iconKey = UniqueKey();
final Icon customIcon = Icon(Icons.assessment, key: iconKey);
......@@ -819,7 +820,7 @@ void main() {
expect(disabledRichText.text.style!.color, Colors.grey.shade400);
});
testWidgets('Dropdown button icon should have the passed in size and color instead of defaults', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown button icon should have the passed in size and color instead of defaults', (WidgetTester tester) async {
final Key iconKey = UniqueKey();
final Icon customIcon = Icon(Icons.assessment, key: iconKey);
......@@ -851,7 +852,7 @@ void main() {
expect(disabledRichText.text.style!.color, Colors.orange);
});
testWidgets('Dropdown button should use its own size and color properties over those defined by the theme', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown button should use its own size and color properties over those defined by the theme', (WidgetTester tester) async {
final Key iconKey = UniqueKey();
final Icon customIcon = Icon(
......@@ -889,7 +890,7 @@ void main() {
expect(disabledRichText.text.style!.color, Colors.yellow);
});
testWidgets('Dropdown button with isDense:true aligns selected menu item', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown button with isDense:true aligns selected menu item', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
Widget build() => buildFrame(buttonKey: buttonKey, isDense: true, onChanged: onChanged);
......@@ -925,7 +926,7 @@ void main() {
checkSelectedItemTextGeometry(tester, 'two');
});
testWidgets('Dropdown button can have a text style with no fontSize specified', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown button can have a text style with no fontSize specified', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/33425
const String value = 'foo';
final UniqueKey itemKey = UniqueKey();
......@@ -952,7 +953,7 @@ void main() {
expect(tester.takeException(), isNull);
});
testWidgets('Dropdown menu scrolls to first item in long lists', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown menu scrolls to first item in long lists', (WidgetTester tester) async {
// Open the dropdown menu
final Key buttonKey = UniqueKey();
await tester.pumpWidget(buildFrame(
......@@ -981,7 +982,7 @@ void main() {
);
});
testWidgets('Dropdown menu aligns selected item with button in long lists', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown menu aligns selected item with button in long lists', (WidgetTester tester) async {
// Open the dropdown menu
final Key buttonKey = UniqueKey();
await tester.pumpWidget(buildFrame(
......@@ -1006,7 +1007,7 @@ void main() {
);
});
testWidgets('Dropdown menu scrolls to last item in long lists', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown menu scrolls to last item in long lists', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
await tester.pumpWidget(buildFrame(
buttonKey: buttonKey,
......@@ -1042,7 +1043,7 @@ void main() {
);
});
testWidgets('Size of DropdownButton with null value', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Size of DropdownButton with null value', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
String? value;
......@@ -1063,7 +1064,7 @@ void main() {
expect(buttonBox.size, equals(buttonBoxNullValue.size));
});
testWidgets('Size of DropdownButton with no items', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Size of DropdownButton with no items', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/26419
final Key buttonKey = UniqueKey();
List<String>? items;
......@@ -1090,7 +1091,7 @@ void main() {
expect(buttonBox.size, equals(buttonBoxNullItems.size));
});
testWidgets('Layout of a DropdownButton with null value', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Layout of a DropdownButton with null value', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
String? value;
......@@ -1118,7 +1119,7 @@ void main() {
expect(value, equals('one'));
});
testWidgets('Size of DropdownButton with null value and a hint', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Size of DropdownButton with null value and a hint', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
String? value;
......@@ -1141,7 +1142,7 @@ void main() {
expect(buttonBox.size, equals(buttonBoxHintValue.size));
});
testWidgets('Dropdown menus must fit within the screen', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown menus must fit within the screen', (WidgetTester tester) async {
// The dropdown menu isn't readily accessible. To find it we're assuming that it
// contains a ListView and that it's an instance of _DropdownMenu.
......@@ -1248,7 +1249,7 @@ void main() {
expect(menuRect.bottomRight, const Offset(800.0, 600.0));
});
testWidgets('Dropdown menus are dismissed on screen orientation changes, but not on keyboard hide', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown menus are dismissed on screen orientation changes, but not on keyboard hide', (WidgetTester tester) async {
await tester.pumpWidget(buildFrame(onChanged: onChanged, mediaSize: const Size(800, 600)));
await tester.tap(find.byType(dropdownButtonType));
await tester.pumpAndSettle();
......@@ -1270,7 +1271,7 @@ void main() {
expect(find.byType(ListView, skipOffstage: false), findsNothing);
});
testWidgets('Semantics Tree contains only selected element', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Semantics Tree contains only selected element', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(buildFrame(onChanged: onChanged));
......@@ -1282,7 +1283,7 @@ void main() {
semantics.dispose();
});
testWidgets('Dropdown button includes semantics', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown button includes semantics', (WidgetTester tester) async {
final SemanticsHandle handle = tester.ensureSemantics();
const Key key = Key('test');
await tester.pumpWidget(buildFrame(
......@@ -1317,7 +1318,7 @@ void main() {
handle.dispose();
});
testWidgets('Dropdown menu includes semantics', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown menu includes semantics', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
const Key key = Key('test');
await tester.pumpWidget(buildFrame(
......@@ -1393,7 +1394,7 @@ void main() {
semantics.dispose();
});
testWidgets('disabledHint displays on empty items or onChanged', (WidgetTester tester) async {
testWidgetsWithLeakTracking('disabledHint displays on empty items or onChanged', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
Widget build({ List<String>? items, ValueChanged<String?>? onChanged }) => buildFrame(
......@@ -1432,7 +1433,7 @@ void main() {
});
// Regression test for https://github.com/flutter/flutter/issues/70177
testWidgets('disabledHint behavior test', (WidgetTester tester) async {
testWidgetsWithLeakTracking('disabledHint behavior test', (WidgetTester tester) async {
Widget build({ List<String>? items, ValueChanged<String?>? onChanged, String? value, Widget? hint, Widget? disabledHint }) => buildFrame(
items: items,
onChanged: onChanged,
......@@ -1489,7 +1490,7 @@ void main() {
expect(getIndex(), null);
});
testWidgets('DropdownButton selected item color test', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton selected item color test', (WidgetTester tester) async {
Widget build({ ValueChanged<String?>? onChanged, String? value, Widget? hint, Widget? disabledHint }) {
return MaterialApp(
theme: ThemeData(
......@@ -1543,7 +1544,7 @@ void main() {
expect(textColor('two'), Colors.pink);
});
testWidgets(
testWidgetsWithLeakTracking(
'DropdownButton hint displays when the items list is empty, '
'items is null, and disabledHint is null',
(WidgetTester tester) async {
......@@ -1567,7 +1568,7 @@ void main() {
},
);
testWidgets('DropdownButton disabledHint is null by default', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton disabledHint is null by default', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
Widget build({ List<String>? items }) {
......@@ -1587,7 +1588,7 @@ void main() {
expect(find.text('hint used when disabled'), findsOneWidget);
});
testWidgets('Size of largest widget is used DropdownButton when selectedItemBuilder is non-null', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Size of largest widget is used DropdownButton when selectedItemBuilder is non-null', (WidgetTester tester) async {
final List<String> items = <String>['25', '50', '100'];
const String selectedItem = '25';
......@@ -1619,7 +1620,7 @@ void main() {
expect(dropdownButtonRenderBox.size.width, 100 + 24.0);
});
testWidgets(
testWidgetsWithLeakTracking(
'Enabled button - Size of largest widget is used DropdownButton when selectedItemBuilder '
'is non-null and hint is defined, but smaller than largest selected item widget',
(WidgetTester tester) async {
......@@ -1657,7 +1658,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'Enabled button - Size of largest widget is used DropdownButton when selectedItemBuilder '
'is non-null and hint is defined, but larger than largest selected item widget',
(WidgetTester tester) async {
......@@ -1699,7 +1700,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'Disabled button - Size of largest widget is used DropdownButton when selectedItemBuilder '
'is non-null, and hint is defined, but smaller than largest selected item widget',
(WidgetTester tester) async {
......@@ -1736,7 +1737,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'Disabled button - Size of largest widget is used DropdownButton when selectedItemBuilder '
'is non-null and hint is defined, but larger than largest selected item widget',
(WidgetTester tester) async {
......@@ -1773,7 +1774,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'Disabled button - Size of largest widget is used DropdownButton when selectedItemBuilder '
'is non-null, and disabledHint is defined, but smaller than largest selected item widget',
(WidgetTester tester) async {
......@@ -1810,7 +1811,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'Disabled button - Size of largest widget is used DropdownButton when selectedItemBuilder '
'is non-null and disabledHint is defined, but larger than largest selected item widget',
(WidgetTester tester) async {
......@@ -1847,7 +1848,7 @@ void main() {
},
);
testWidgets('Dropdown in middle showing middle item', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown in middle showing middle item', (WidgetTester tester) async {
final List<DropdownMenuItem<int>> items = List<DropdownMenuItem<int>>.generate(
100,
(int i) => DropdownMenuItem<int>(value: i, child: Text('$i')),
......@@ -1881,7 +1882,7 @@ void main() {
expect(getMenuScroll(), 2180.0);
});
testWidgets('Dropdown in top showing bottom item', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown in top showing bottom item', (WidgetTester tester) async {
final List<DropdownMenuItem<int>> items = List<DropdownMenuItem<int>>.generate(
100,
(int i) => DropdownMenuItem<int>(value: i, child: Text('$i')),
......@@ -1916,7 +1917,7 @@ void main() {
expect(getMenuScroll(), 4312.0);
});
testWidgets('Dropdown in bottom showing top item', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown in bottom showing top item', (WidgetTester tester) async {
final List<DropdownMenuItem<int>> items = List<DropdownMenuItem<int>>.generate(
100,
(int i) => DropdownMenuItem<int>(value: i, child: Text('$i')),
......@@ -1951,7 +1952,7 @@ void main() {
expect(getMenuScroll(), 0.0);
});
testWidgets('Dropdown in center showing bottom item', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown in center showing bottom item', (WidgetTester tester) async {
final List<DropdownMenuItem<int>> items = List<DropdownMenuItem<int>>.generate(
100,
(int i) => DropdownMenuItem<int>(value: i, child: Text('$i')),
......@@ -1985,7 +1986,7 @@ void main() {
expect(getMenuScroll(), 4312.0);
});
testWidgets('Dropdown menu respects parent size limits', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown menu respects parent size limits', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/24417
int? selectedIndex;
await tester.pumpWidget(
......@@ -2031,7 +2032,7 @@ void main() {
expect(selectedIndex, 13);
});
testWidgets('Dropdown button will accept widgets as its underline', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown button will accept widgets as its underline', (WidgetTester tester) async {
const BoxDecoration decoration = BoxDecoration(
border: Border(bottom: BorderSide(color: Color(0xFFCCBB00), width: 4.0)),
);
......@@ -2058,7 +2059,7 @@ void main() {
expect(tester.widgetList<DecoratedBox>(decoratedBox).last.decoration, defaultDecoration);
});
testWidgets('DropdownButton selectedItemBuilder builds custom buttons', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton selectedItemBuilder builds custom buttons', (WidgetTester tester) async {
const List<String> items = <String>[
'One',
'Two',
......@@ -2104,19 +2105,19 @@ void main() {
expect(find.text('Two as an Arabic numeral: 2'), findsOneWidget);
});
testWidgets('DropdownButton uses default color when expanded', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton uses default color when expanded', (WidgetTester tester) async {
await checkDropdownColor(tester);
});
testWidgets('DropdownButton uses dropdownColor when expanded', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton uses dropdownColor when expanded', (WidgetTester tester) async {
await checkDropdownColor(tester, color: const Color.fromRGBO(120, 220, 70, 0.8));
});
testWidgets('DropdownButtonFormField uses dropdownColor when expanded', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButtonFormField uses dropdownColor when expanded', (WidgetTester tester) async {
await checkDropdownColor(tester, color: const Color.fromRGBO(120, 220, 70, 0.8), isFormField: true);
});
testWidgets('DropdownButton hint displays properly when selectedItemBuilder is defined', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton hint displays properly when selectedItemBuilder is defined', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/42340
final List<String> items = <String>['1', '2', '3'];
String? selectedItem;
......@@ -2162,7 +2163,7 @@ void main() {
expect(find.text('You have selected: 1'), findsOneWidget);
});
testWidgets('Variable size and oversized menu items', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Variable size and oversized menu items', (WidgetTester tester) async {
final List<double> itemHeights = <double>[30, 40, 50, 60];
double? dropdownValue = itemHeights[0];
......@@ -2261,7 +2262,7 @@ void main() {
expect(tester.getCenter(item40.first).dy, tester.getCenter(item40.last).dy);
});
testWidgets('DropdownButton menu items do not resize when its route is popped', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton menu items do not resize when its route is popped', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/44877.
const List<String> items = <String>[
'one',
......@@ -2317,7 +2318,7 @@ void main() {
expect(find.text('two'), findsOneWidget);
});
testWidgets('DropdownButton hint is selected item', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton hint is selected item', (WidgetTester tester) async {
const double hintPaddingOffset = 8;
const List<String> itemValues = <String>['item0', 'item1', 'item2', 'item3'];
String? selectedItem = 'item0';
......@@ -2385,10 +2386,12 @@ void main() {
expect(tester.getTopLeft(find.text('-item0-')).dx, 8);
});
testWidgets('DropdownButton can be focused, and has focusColor', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton can be focused, and has focusColor', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
final UniqueKey buttonKey = UniqueKey();
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton');
addTearDown(focusNode.dispose);
await tester.pumpWidget(buildFrame(buttonKey: buttonKey, onChanged: onChanged, focusNode: focusNode, autofocus: true, useMaterial3: false));
await tester.pumpAndSettle(); // Pump a frame for autofocus to take effect.
expect(focusNode.hasPrimaryFocus, isTrue);
......@@ -2399,10 +2402,12 @@ void main() {
expect(find.byType(Material), paints..rect(rect: const Rect.fromLTRB(348.0, 276.0, 452.0, 324.0), color: const Color(0x1f00ff00)));
});
testWidgets('DropdownButtonFormField can be focused, and has focusColor', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButtonFormField can be focused, and has focusColor', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
final UniqueKey buttonKey = UniqueKey();
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButtonFormField');
addTearDown(focusNode.dispose);
await tester.pumpWidget(buildFrame(isFormField: true, buttonKey: buttonKey, onChanged: onChanged, focusNode: focusNode, autofocus: true));
await tester.pumpAndSettle(); // Pump a frame for autofocus to take effect.
expect(focusNode.hasPrimaryFocus, isTrue);
......@@ -2413,17 +2418,20 @@ void main() {
expect(find.byType(Material), paints ..rect(rect: const Rect.fromLTRB(0.0, 264.0, 800.0, 336.0), color: const Color(0x1f00ff00)));
});
testWidgets("DropdownButton won't be focused if not enabled", (WidgetTester tester) async {
testWidgetsWithLeakTracking("DropdownButton won't be focused if not enabled", (WidgetTester tester) async {
final UniqueKey buttonKey = UniqueKey();
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton');
addTearDown(focusNode.dispose);
await tester.pumpWidget(buildFrame(buttonKey: buttonKey, focusNode: focusNode, autofocus: true, focusColor: const Color(0xff00ff00)));
await tester.pump(); // Pump a frame for autofocus to take effect (although it shouldn't).
expect(focusNode.hasPrimaryFocus, isFalse);
expect(find.byKey(buttonKey), isNot(paints ..rrect(rrect: const RRect.fromLTRBXY(0.0, 0.0, 104.0, 48.0, 4.0, 4.0), color: const Color(0xff00ff00))));
});
testWidgets('DropdownButton is activated with the enter key', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton is activated with the enter key', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton');
addTearDown(focusNode.dispose);
String? value = 'one';
Widget buildFrame() {
......@@ -2478,7 +2486,7 @@ void main() {
});
// Regression test for https://github.com/flutter/flutter/issues/77655.
testWidgets('DropdownButton selecting a null valued item should be selected', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton selecting a null valued item should be selected', (WidgetTester tester) async {
final List<MapEntry<String?, String>> items = <MapEntry<String?, String>>[
const MapEntry<String?, String>(null, 'None'),
const MapEntry<String?, String>('one', 'One'),
......@@ -2518,8 +2526,9 @@ void main() {
expect(find.text('None'), findsOneWidget);
});
testWidgets('DropdownButton is activated with the space key', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton is activated with the space key', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton');
addTearDown(focusNode.dispose);
String? value = 'one';
Widget buildFrame() {
......@@ -2573,8 +2582,9 @@ void main() {
expect(value, equals('two'));
});
testWidgets('Selected element is focused when dropdown is opened', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Selected element is focused when dropdown is opened', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton');
addTearDown(focusNode.dispose);
String? value = 'one';
await tester.pumpWidget(MaterialApp(
home: Scaffold(
......@@ -2633,8 +2643,9 @@ void main() {
expect(node.hasFocus, isTrue);
});
testWidgets('Selected element is correctly focused with dropdown that more items than fit on the screen', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Selected element is correctly focused with dropdown that more items than fit on the screen', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton');
addTearDown(focusNode.dispose);
int? value = 1;
final List<int> hugeMenuItems = List<int>.generate(50, (int index) => index);
......@@ -2696,8 +2707,9 @@ void main() {
expect(node.hasFocus, isTrue);
});
testWidgets("Having a focused element doesn't interrupt scroll when flung by touch", (WidgetTester tester) async {
testWidgetsWithLeakTracking("Having a focused element doesn't interrupt scroll when flung by touch", (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton');
addTearDown(focusNode.dispose);
int? value = 1;
final List<int> hugeMenuItems = List<int>.generate(100, (int index) => index);
......@@ -2771,8 +2783,9 @@ void main() {
expect(Focus.of(tester.element(find.byKey(const ValueKey<int>(91), skipOffstage: false).last)).hasPrimaryFocus, isFalse);
});
testWidgets('DropdownButton onTap callback can request focus', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton onTap callback can request focus', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton')..addListener(() { });
addTearDown(focusNode.dispose);
int? value = 1;
final List<int> hugeMenuItems = List<int>.generate(100, (int index) => index);
......@@ -2819,8 +2832,9 @@ void main() {
expect(focusNode.hasPrimaryFocus, isTrue);
});
testWidgets('DropdownButton changes selected item with arrow keys', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton changes selected item with arrow keys', (WidgetTester tester) async {
final FocusNode focusNode = FocusNode(debugLabel: 'DropdownButton');
addTearDown(focusNode.dispose);
String? value = 'one';
Widget buildFrame() {
......@@ -2878,7 +2892,7 @@ void main() {
expect(value, equals('two'));
});
testWidgets('DropdownButton onTap callback is called when defined', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton onTap callback is called when defined', (WidgetTester tester) async {
int dropdownButtonTapCounter = 0;
String? value = 'one';
......@@ -2923,7 +2937,7 @@ void main() {
expect(dropdownButtonTapCounter, 2); // Should not change.
});
testWidgets('DropdownMenuItem onTap callback is called when defined', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownMenuItem onTap callback is called when defined', (WidgetTester tester) async {
String? value = 'one';
final List<int> menuItemTapCounters = <int>[0, 0, 0, 0];
void onChanged(String? newValue) { value = newValue; }
......@@ -3008,7 +3022,7 @@ void main() {
expect(menuItemTapCounters, <int>[0, 2, 1, 0]);
});
testWidgets('Does not crash when option is selected without waiting for opening animation to complete', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Does not crash when option is selected without waiting for opening animation to complete', (WidgetTester tester) async {
// Regression test for b/171846624.
final List<String> options = <String>['first', 'second', 'third'];
......@@ -3056,7 +3070,7 @@ void main() {
expect(find.text('second').hitTestable(), findsNothing);
});
testWidgets('Dropdown menu should persistently show a scrollbar if it is scrollable', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown menu should persistently show a scrollbar if it is scrollable', (WidgetTester tester) async {
await tester.pumpWidget(buildFrame(
value: '0',
// menu is short enough to fit onto the screen.
......@@ -3088,7 +3102,7 @@ void main() {
expect(find.byType(Scrollbar), paints..rect());
});
testWidgets("Dropdown menu's maximum height should be influenced by DropdownButton.menuMaxHeight.", (WidgetTester tester) async {
testWidgetsWithLeakTracking("Dropdown menu's maximum height should be influenced by DropdownButton.menuMaxHeight.", (WidgetTester tester) async {
await tester.pumpWidget(buildFrame(
value: '0',
items: List<String>.generate(/*length=*/64, (int index) => index.toString()),
......@@ -3142,7 +3156,7 @@ void main() {
});
// Regression test for https://github.com/flutter/flutter/issues/89029
testWidgets('menu position test with `menuMaxHeight`', (WidgetTester tester) async {
testWidgetsWithLeakTracking('menu position test with `menuMaxHeight`', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
await tester.pumpWidget(buildFrame(
buttonKey: buttonKey,
......@@ -3165,7 +3179,7 @@ void main() {
});
// Regression test for https://github.com/flutter/flutter/issues/76614
testWidgets('Do not crash if used in very short screen', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Do not crash if used in very short screen', (WidgetTester tester) async {
// The default item height is 48.0 pixels and needs two items padding since
// the menu requires empty space surrounding the menu. Finally, the constraint height
// is 47.0 pixels for the menu rendering.
......@@ -3221,7 +3235,7 @@ void main() {
);
});
testWidgets('Tapping a disabled item should not close DropdownButton', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tapping a disabled item should not close DropdownButton', (WidgetTester tester) async {
String? value = 'first';
await tester.pumpWidget(
......@@ -3267,7 +3281,7 @@ void main() {
expect(find.text('second').hitTestable(), findsOneWidget);
});
testWidgets('Disabled item should not be focusable', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Disabled item should not be focusable', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
......@@ -3298,7 +3312,7 @@ void main() {
expect(Focus.maybeOf(disabledItem), null, reason: 'Disabled menu item should not be able to request focus');
});
testWidgets('alignment test', (WidgetTester tester) async {
testWidgetsWithLeakTracking('alignment test', (WidgetTester tester) async {
final Key buttonKey = UniqueKey();
Widget buildFrame({AlignmentGeometry? buttonAlignment, AlignmentGeometry? menuAlignment}) {
return MaterialApp(
......@@ -3402,7 +3416,7 @@ void main() {
);
}
testWidgets('Dropdown with enabled feedback', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown with enabled feedback', (WidgetTester tester) async {
const bool enableFeedback = true;
await tester.pumpWidget(feedbackBoilerplate(enableFeedback: enableFeedback));
......@@ -3415,7 +3429,7 @@ void main() {
expect(feedback.hapticCount, 0);
});
testWidgets('Dropdown with disabled feedback', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown with disabled feedback', (WidgetTester tester) async {
const bool enableFeedback = false;
await tester.pumpWidget(feedbackBoilerplate(enableFeedback: enableFeedback));
......@@ -3428,7 +3442,7 @@ void main() {
expect(feedback.hapticCount, 0);
});
testWidgets('Dropdown with enabled feedback by default', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Dropdown with enabled feedback by default', (WidgetTester tester) async {
await tester.pumpWidget(feedbackBoilerplate());
await tester.tap(find.text('One'));
......@@ -3440,7 +3454,7 @@ void main() {
});
});
testWidgets('DropdownButton changes mouse cursor when hovered', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton changes mouse cursor when hovered', (WidgetTester tester) async {
const Key key = Key('testDropdownButton');
await tester.pumpWidget(
MaterialApp(
......@@ -3498,7 +3512,7 @@ void main() {
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
});
testWidgets('Conflicting scrollbars are not applied by ScrollBehavior to Dropdown', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Conflicting scrollbars are not applied by ScrollBehavior to Dropdown', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/83819
// Open the dropdown menu
final Key buttonKey = UniqueKey();
......@@ -3521,7 +3535,7 @@ void main() {
}, variant: TargetPlatformVariant.all());
testWidgets('borderRadius property works properly', (WidgetTester tester) async {
testWidgetsWithLeakTracking('borderRadius property works properly', (WidgetTester tester) async {
const double radius = 20.0;
await tester.pumpWidget(
......@@ -3564,7 +3578,7 @@ void main() {
});
// Regression test for https://github.com/flutter/flutter/issues/88574
testWidgets("specifying itemHeight affects popup menu items' height", (WidgetTester tester) async {
testWidgetsWithLeakTracking("specifying itemHeight affects popup menu items' height", (WidgetTester tester) async {
const String value = 'One';
const double itemHeight = 80;
final List<DropdownMenuItem<String>> menuItems = <String>[
......@@ -3605,7 +3619,7 @@ void main() {
});
// Regression test for https://github.com/flutter/flutter/issues/92438
testWidgets('Do not throw due to the double precision', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Do not throw due to the double precision', (WidgetTester tester) async {
const String value = 'One';
const double itemHeight = 77.701;
final List<DropdownMenuItem<String>> menuItems = <String>[
......@@ -3639,7 +3653,7 @@ void main() {
expect(tester.takeException(), null);
});
testWidgets('BorderRadius property works properly for DropdownButtonFormField', (WidgetTester tester) async {
testWidgetsWithLeakTracking('BorderRadius property works properly for DropdownButtonFormField', (WidgetTester tester) async {
const double radius = 20.0;
await tester.pumpWidget(
......@@ -3680,7 +3694,7 @@ void main() {
);
});
testWidgets('DropdownButton hint alignment', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton hint alignment', (WidgetTester tester) async {
const String hintText = 'hint';
// AlignmentDirectional.centerStart (default)
......@@ -3785,7 +3799,7 @@ void main() {
expect(tester.getBottomRight(find.text(hintText,skipOffstage: false)).dy, 350.0);
});
testWidgets('DropdownButton hint alignment with selectedItemBuilder', (WidgetTester tester) async {
testWidgetsWithLeakTracking('DropdownButton hint alignment with selectedItemBuilder', (WidgetTester tester) async {
const String hintText = 'hint';
// AlignmentDirectional.centerStart (default)
......@@ -3904,7 +3918,7 @@ void main() {
expect(tester.getBottomRight(find.text(hintText,skipOffstage: false)).dy, 350.0);
});
testWidgets('BorderRadius property clips dropdown button and dropdown menu', (WidgetTester tester) async {
testWidgetsWithLeakTracking('BorderRadius property clips dropdown button and dropdown menu', (WidgetTester tester) async {
const double radius = 20.0;
await tester.pumpWidget(
......@@ -3943,7 +3957,7 @@ void main() {
expect(renderClip.borderRadius, BorderRadius.circular(radius));
});
testWidgets('Size of DropdownButton with padding', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Size of DropdownButton with padding', (WidgetTester tester) async {
const double padVertical = 5;
const double padHorizontal = 10;
final Key buttonKey = UniqueKey();
......
......@@ -1782,6 +1782,7 @@ void main() {
count += 1;
}
final MaterialStatesController controller = MaterialStatesController();
addTearDown(controller.dispose);
controller.addListener(valueChanged);
await tester.pumpWidget(
......@@ -1882,21 +1883,23 @@ void main() {
await gesture.removePointer();
}
testWidgets('ElevatedButton statesController', (WidgetTester tester) async {
testWidgetsWithLeakTracking('ElevatedButton statesController', (WidgetTester tester) async {
testStatesController(null, tester);
});
testWidgets('ElevatedButton.icon statesController', (WidgetTester tester) async {
testWidgetsWithLeakTracking('ElevatedButton.icon statesController', (WidgetTester tester) async {
testStatesController(const Icon(Icons.add), tester);
});
testWidgets('Disabled ElevatedButton statesController', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Disabled ElevatedButton statesController', (WidgetTester tester) async {
int count = 0;
void valueChanged() {
count += 1;
}
final MaterialStatesController controller = MaterialStatesController();
addTearDown(controller.dispose);
controller.addListener(valueChanged);
await tester.pumpWidget(
MaterialApp(
home: Center(
......
......@@ -589,7 +589,7 @@ void main() {
});
// Regression test for https://github.com/flutter/flutter/issues/71435
testWidgets(
testWidgetsWithLeakTracking(
'Scaffold.bottomSheet should be updated without creating a new RO'
' when the new widget has the same key and type.',
(WidgetTester tester) async {
......
......@@ -1134,7 +1134,7 @@ void main() {
expect(snackBarBottomRight.dy - actionTextBottomRight.dy, 14.0 + 40.0); // margin + bottom padding
});
testWidgets(
testWidgetsWithLeakTracking(
'Material2 - Custom padding between SnackBar and its contents when set to SnackBarBehavior.fixed',
(WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
......@@ -1191,7 +1191,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'Material3 - Custom padding between SnackBar and its contents when set to SnackBarBehavior.fixed',
(WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
......@@ -1405,7 +1405,7 @@ void main() {
expect(snackBarBottomRight.dy - actionTextBottomRight.dy, 24.0); // margin (with no bottom padding)
});
testWidgets(
testWidgetsWithLeakTracking(
'Material2 - Custom padding between SnackBar and its contents when set to SnackBarBehavior.floating',
(WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
......@@ -1465,7 +1465,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'Material3 - Custom padding between SnackBar and its contents when set to SnackBarBehavior.floating',
(WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
......@@ -1873,7 +1873,7 @@ void main() {
behavior: behavior,
);
testWidgets(
testWidgetsWithLeakTracking(
'$behavior should align SnackBar with the bottom of Scaffold '
'when Scaffold has no other elements',
(WidgetTester tester) async {
......@@ -1902,7 +1902,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'$behavior should align SnackBar with the top of BottomNavigationBar '
'when Scaffold has no FloatingActionButton',
(WidgetTester tester) async {
......@@ -1934,7 +1934,7 @@ void main() {
);
}
testWidgets(
testWidgetsWithLeakTracking(
'Padding of ${SnackBarBehavior.fixed} is not consumed by viewInsets',
(WidgetTester tester) async {
final Widget child = MaterialApp(
......@@ -1997,7 +1997,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'${SnackBarBehavior.fixed} should align SnackBar with the bottom of Scaffold '
'when Scaffold has a FloatingActionButton',
(WidgetTester tester) async {
......@@ -2032,7 +2032,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'${SnackBarBehavior.floating} should align SnackBar with the top of FloatingActionButton when Scaffold has a FloatingActionButton',
(WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
......@@ -2072,7 +2072,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'${SnackBarBehavior.floating} should not align SnackBar with the top of FloatingActionButton '
'when Scaffold has a FloatingActionButton and floatingActionButtonLocation is set to a top position',
(WidgetTester tester) async {
......@@ -2125,7 +2125,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'${SnackBarBehavior.floating} should align SnackBar with the top of FloatingActionButton '
'when Scaffold has a FloatingActionButton and floatingActionButtonLocation is not set to a top position',
(WidgetTester tester) async {
......@@ -2193,7 +2193,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'${SnackBarBehavior.fixed} should align SnackBar with the top of BottomNavigationBar '
'when Scaffold has a BottomNavigationBar and FloatingActionButton',
(WidgetTester tester) async {
......@@ -2230,7 +2230,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'${SnackBarBehavior.floating} should align SnackBar with the top of FloatingActionButton '
'when Scaffold has BottomNavigationBar and FloatingActionButton',
(WidgetTester tester) async {
......@@ -2400,7 +2400,7 @@ void main() {
expect(errorMessages.contains(offScreenMessage), isTrue);
});
testWidgets(
testWidgetsWithLeakTracking(
'SnackBar has correct end padding when it contains an action with fixed behavior',
(WidgetTester tester) async {
await tester.pumpWidget(
......@@ -2437,7 +2437,7 @@ void main() {
},
);
testWidgets(
testWidgetsWithLeakTracking(
'SnackBar has correct end padding when it contains an action with floating behavior',
(WidgetTester tester) async {
await tester.pumpWidget(
......@@ -3337,7 +3337,7 @@ void main() {
);
});
testWidgets(
testWidgetsWithLeakTracking(
'ScaffoldMessenger will alert for snackbars that cannot be presented', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/103004
await tester.pumpWidget(const MaterialApp(
......@@ -3723,7 +3723,7 @@ testWidgetsWithLeakTracking('SnackBarAction backgroundColor works as a Color', (
expect(completer.isCompleted, true);
});
testWidgets("Can't tap on button behind snack bar defined by margin and HitTestBehavior.opaque", (WidgetTester tester) async {
testWidgetsWithLeakTracking("Can't tap on button behind snack bar defined by margin and HitTestBehavior.opaque", (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/78537.
tester.view.physicalSize = const Size.square(200);
tester.view.devicePixelRatio = 1;
......
......@@ -11,6 +11,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
const String _tab1Text = 'tab 1';
const String _tab2Text = 'tab 2';
......@@ -36,6 +37,12 @@ Widget buildTabBar({
bool isScrollable = false,
bool useMaterial3 = false,
}) {
final TabController controller = TabController(
length: tabs.length,
vsync: const TestVSync(),
);
addTearDown(controller.dispose);
if (secondaryTabBar) {
return MaterialApp(
theme: ThemeData(tabBarTheme: tabBarTheme, useMaterial3: useMaterial3),
......@@ -45,7 +52,7 @@ Widget buildTabBar({
child: TabBar.secondary(
tabs: tabs,
isScrollable: isScrollable,
controller: TabController(length: tabs.length, vsync: const TestVSync()),
controller: controller,
),
),
),
......@@ -59,7 +66,7 @@ Widget buildTabBar({
child: TabBar(
tabs: tabs,
isScrollable: isScrollable,
controller: TabController(length: tabs.length, vsync: const TestVSync()),
controller: controller,
),
),
),
......@@ -103,7 +110,7 @@ void main() {
expect(identical(TabBarTheme.lerp(theme, theme, 0.5), theme), true);
});
testWidgets('Tab bar defaults (primary)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar defaults (primary)', (WidgetTester tester) async {
// Test default label color and label styles.
await tester.pumpWidget(buildTabBar(useMaterial3: true));
......@@ -154,7 +161,7 @@ void main() {
);
});
testWidgets('Tab bar defaults (secondary)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar defaults (secondary)', (WidgetTester tester) async {
// Test default label color and label styles.
await tester.pumpWidget(buildTabBar(secondaryTabBar: true, useMaterial3: true));
......@@ -210,7 +217,7 @@ void main() {
);
});
testWidgets('Tab bar theme overrides label color (selected)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar theme overrides label color (selected)', (WidgetTester tester) async {
const Color labelColor = Colors.black;
const TabBarTheme tabBarTheme = TabBarTheme(labelColor: labelColor);
......@@ -222,7 +229,7 @@ void main() {
expect(tabIcon.text.style!.color, equals(labelColor));
});
testWidgets('Tab bar theme overrides label padding', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar theme overrides label padding', (WidgetTester tester) async {
const double topPadding = 10.0;
const double bottomPadding = 7.0;
const double rightPadding = 13.0;
......@@ -259,7 +266,7 @@ void main() {
expect(tabOneRect.right, equals(tabTwoRect.left - leftPadding - rightPadding));
});
testWidgets('Tab bar theme overrides label styles', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar theme overrides label styles', (WidgetTester tester) async {
const TextStyle labelStyle = TextStyle(fontFamily: 'foobar');
const TextStyle unselectedLabelStyle = TextStyle(fontFamily: 'baz');
const TabBarTheme tabBarTheme = TabBarTheme(
......@@ -275,7 +282,7 @@ void main() {
expect(unselectedLabel.text.style!.fontFamily, equals(unselectedLabelStyle.fontFamily));
});
testWidgets('Tab bar theme with just label style specified', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar theme with just label style specified', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/28784
const TextStyle labelStyle = TextStyle(fontFamily: 'foobar');
const TabBarTheme tabBarTheme = TabBarTheme(
......@@ -292,7 +299,7 @@ void main() {
expect(unselectedLabel.text.style!.color, equals(Colors.white.withAlpha(0xB2)));
});
testWidgets('Tab bar label styles override theme label styles', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar label styles override theme label styles', (WidgetTester tester) async {
const TextStyle labelStyle = TextStyle(fontFamily: '1');
const TextStyle unselectedLabelStyle = TextStyle(fontFamily: '2');
const TextStyle themeLabelStyle = TextStyle(fontFamily: '3');
......@@ -301,6 +308,11 @@ void main() {
labelStyle: themeLabelStyle,
unselectedLabelStyle: themeUnselectedLabelStyle,
);
final TabController controller = TabController(
length: _tabs.length,
vsync: const TestVSync(),
);
addTearDown(controller.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -308,7 +320,7 @@ void main() {
home: Scaffold(
body: TabBar(
tabs: _tabs,
controller: TabController(length: _tabs.length, vsync: const TestVSync()),
controller: controller,
labelStyle: labelStyle,
unselectedLabelStyle: unselectedLabelStyle,
),
......@@ -322,7 +334,7 @@ void main() {
expect(unselectedLabel.text.style!.fontFamily, equals(unselectedLabelStyle.fontFamily));
});
testWidgets('Material2 - Tab bar label padding overrides theme label padding', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Material2 - Tab bar label padding overrides theme label padding', (WidgetTester tester) async {
const double verticalPadding = 10.0;
const double horizontalPadding = 10.0;
const EdgeInsetsGeometry labelPadding = EdgeInsets.symmetric(
......@@ -341,6 +353,12 @@ void main() {
const TabBarTheme tabBarTheme = TabBarTheme(labelPadding: themeLabelPadding);
final TabController controller = TabController(
length: _sizedTabs.length,
vsync: const TestVSync(),
);
addTearDown(controller.dispose);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(tabBarTheme: tabBarTheme, useMaterial3: false),
......@@ -350,7 +368,7 @@ void main() {
child: TabBar(
tabs: _sizedTabs,
isScrollable: true,
controller: TabController(length: _sizedTabs.length, vsync: const TestVSync()),
controller: controller,
labelPadding: labelPadding,
),
),
......@@ -376,7 +394,7 @@ void main() {
expect(tabOneRect.right, equals(tabTwoRect.left - (2 * horizontalPadding)));
});
testWidgets('Material3 - Tab bar label padding overrides theme label padding', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Material3 - Tab bar label padding overrides theme label padding', (WidgetTester tester) async {
const double tabStartOffset = 52.0;
const double verticalPadding = 10.0;
const double horizontalPadding = 10.0;
......@@ -396,6 +414,12 @@ void main() {
const TabBarTheme tabBarTheme = TabBarTheme(labelPadding: themeLabelPadding);
final TabController controller = TabController(
length: _sizedTabs.length,
vsync: const TestVSync(),
);
addTearDown(controller.dispose);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(tabBarTheme: tabBarTheme, useMaterial3: true),
......@@ -405,7 +429,7 @@ void main() {
child: TabBar(
tabs: _sizedTabs,
isScrollable: true,
controller: TabController(length: _sizedTabs.length, vsync: const TestVSync()),
controller: controller,
labelPadding: labelPadding,
),
),
......@@ -431,7 +455,7 @@ void main() {
expect(tabOneRect.right, equals(tabTwoRect.left - (2 * horizontalPadding)));
});
testWidgets('Tab bar theme overrides label color (unselected)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar theme overrides label color (unselected)', (WidgetTester tester) async {
const Color unselectedLabelColor = Colors.black;
const TabBarTheme tabBarTheme = TabBarTheme(unselectedLabelColor: unselectedLabelColor);
......@@ -443,7 +467,7 @@ void main() {
expect(iconRenderObject.text.style!.color, equals(unselectedLabelColor));
});
testWidgets('Tab bar default tab indicator size (primary)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar default tab indicator size (primary)', (WidgetTester tester) async {
await tester.pumpWidget(buildTabBar(useMaterial3: true, isScrollable: true));
await expectLater(
......@@ -452,7 +476,7 @@ void main() {
);
});
testWidgets('Tab bar default tab indicator size (secondary)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar default tab indicator size (secondary)', (WidgetTester tester) async {
await tester.pumpWidget(buildTabBar(useMaterial3: true, isScrollable: true));
await expectLater(
......@@ -461,7 +485,7 @@ void main() {
);
});
testWidgets('Tab bar theme overrides tab indicator size (tab)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar theme overrides tab indicator size (tab)', (WidgetTester tester) async {
const TabBarTheme tabBarTheme = TabBarTheme(indicatorSize: TabBarIndicatorSize.tab);
await tester.pumpWidget(buildTabBar(tabBarTheme: tabBarTheme));
......@@ -472,7 +496,7 @@ void main() {
);
});
testWidgets('Tab bar theme overrides tab indicator size (label)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar theme overrides tab indicator size (label)', (WidgetTester tester) async {
const TabBarTheme tabBarTheme = TabBarTheme(indicatorSize: TabBarIndicatorSize.label);
await tester.pumpWidget(buildTabBar(tabBarTheme: tabBarTheme));
......@@ -483,7 +507,7 @@ void main() {
);
});
testWidgets('Tab bar theme overrides tab mouse cursor', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar theme overrides tab mouse cursor', (WidgetTester tester) async {
const TabBarTheme tabBarTheme = TabBarTheme(mouseCursor: MaterialStateMouseCursor.textable);
await tester.pumpWidget(buildTabBar(tabBarTheme: tabBarTheme));
......@@ -498,7 +522,7 @@ void main() {
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
});
testWidgets('Tab bar theme - custom tab indicator', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar theme - custom tab indicator', (WidgetTester tester) async {
final TabBarTheme tabBarTheme = TabBarTheme(
indicator: BoxDecoration(
border: Border.all(),
......@@ -513,7 +537,7 @@ void main() {
);
});
testWidgets('Tab bar theme - beveled rect indicator', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar theme - beveled rect indicator', (WidgetTester tester) async {
const TabBarTheme tabBarTheme = TabBarTheme(
indicator: ShapeDecoration(
shape: BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20.0))),
......@@ -529,7 +553,7 @@ void main() {
);
});
testWidgets('TabAlignment.fill from TabBarTheme only supports non-scrollable tab bar', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TabAlignment.fill from TabBarTheme only supports non-scrollable tab bar', (WidgetTester tester) async {
const TabBarTheme tabBarTheme = TabBarTheme(tabAlignment: TabAlignment.fill);
// Test TabAlignment.fill from TabBarTheme with non-scrollable tab bar.
......@@ -543,7 +567,7 @@ void main() {
expect(tester.takeException(), isAssertionError);
});
testWidgets(
testWidgetsWithLeakTracking(
'TabAlignment.start & TabAlignment.startOffset from TabBarTheme only supports scrollable tab bar',
(WidgetTester tester) async {
TabBarTheme tabBarTheme = const TabBarTheme(tabAlignment: TabAlignment.start);
......@@ -571,7 +595,7 @@ void main() {
expect(tester.takeException(), isAssertionError);
});
testWidgets('TabBarTheme.indicatorSize provides correct tab indicator (primary)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TabBarTheme.indicatorSize provides correct tab indicator (primary)', (WidgetTester tester) async {
final ThemeData theme = ThemeData(
tabBarTheme: const TabBarTheme(indicatorSize: TabBarIndicatorSize.tab),
useMaterial3: true,
......@@ -584,6 +608,7 @@ void main() {
vsync: const TestVSync(),
length: tabs.length,
);
addTearDown(controller.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -626,7 +651,7 @@ void main() {
);
});
testWidgets('TabBarTheme.indicatorSize provides correct tab indicator (secondary)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TabBarTheme.indicatorSize provides correct tab indicator (secondary)', (WidgetTester tester) async {
final ThemeData theme = ThemeData(
tabBarTheme: const TabBarTheme(indicatorSize: TabBarIndicatorSize.label),
useMaterial3: true,
......@@ -639,6 +664,7 @@ void main() {
vsync: const TestVSync(),
length: tabs.length,
);
addTearDown(controller.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -679,10 +705,16 @@ void main() {
);
});
testWidgets('TabBar divider can use TabBarTheme.dividerColor & TabBarTheme.dividerHeight', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TabBar divider can use TabBarTheme.dividerColor & TabBarTheme.dividerHeight', (WidgetTester tester) async {
const Color dividerColor = Color(0xff00ff00);
const double dividerHeight = 10.0;
final TabController controller = TabController(
length: 3,
vsync: const TestVSync(),
);
addTearDown(controller.dispose);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
......@@ -695,7 +727,7 @@ void main() {
home: Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: TabController(length: 3, vsync: const TestVSync()),
controller: controller,
tabs: const <Widget>[
Tab(text: 'Tab 1'),
Tab(text: 'Tab 2'),
......@@ -712,10 +744,16 @@ void main() {
expect(tabBarBox, paints..line(color: dividerColor, strokeWidth: dividerHeight));
});
testWidgets('dividerColor & dividerHeight overrides TabBarTheme.dividerColor', (WidgetTester tester) async {
testWidgetsWithLeakTracking('dividerColor & dividerHeight overrides TabBarTheme.dividerColor', (WidgetTester tester) async {
const Color dividerColor = Color(0xff0000ff);
const double dividerHeight = 8.0;
final TabController controller = TabController(
length: 3,
vsync: const TestVSync(),
);
addTearDown(controller.dispose);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
......@@ -730,7 +768,7 @@ void main() {
bottom: TabBar(
dividerColor: dividerColor,
dividerHeight: dividerHeight,
controller: TabController(length: 3, vsync: const TestVSync()),
controller: controller,
tabs: const <Widget>[
Tab(text: 'Tab 1'),
Tab(text: 'Tab 2'),
......@@ -747,7 +785,13 @@ void main() {
expect(tabBarBox, paints..line(color: dividerColor, strokeWidth: dividerHeight));
});
testWidgets('TabBar respects TabBarTheme.tabAlignment', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TabBar respects TabBarTheme.tabAlignment', (WidgetTester tester) async {
final TabController controller1 = TabController(
length: 2,
vsync: const TestVSync(),
);
addTearDown(controller1.dispose);
// Test non-scrollable tab bar.
await tester.pumpWidget(
MaterialApp(
......@@ -758,7 +802,7 @@ void main() {
home: Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: TabController(length: 2, vsync: const TestVSync()),
controller: controller1,
tabs: const <Widget>[
Tab(text: 'Tab 1'),
Tab(text: 'Tab 3'),
......@@ -778,6 +822,12 @@ void main() {
double tabTwoRight = (availableWidth / 2) + tabTwoRect.width + kTabLabelPadding.right;
expect(tabTwoRect.right, equals(tabTwoRight));
final TabController controller2 = TabController(
length: 2,
vsync: const TestVSync(),
);
addTearDown(controller2.dispose);
// Test scrollable tab bar.
await tester.pumpWidget(
MaterialApp(
......@@ -789,7 +839,7 @@ void main() {
appBar: AppBar(
bottom: TabBar(
isScrollable: true,
controller: TabController(length: 2, vsync: const TestVSync()),
controller: controller2,
tabs: const <Widget>[
Tab(text: 'Tab 1'),
Tab(text: 'Tab 3'),
......@@ -810,7 +860,13 @@ void main() {
expect(tabTwoRect.right, equals(tabTwoRight));
});
testWidgets('TabBar.tabAlignment overrides TabBarTheme.tabAlignment', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TabBar.tabAlignment overrides TabBarTheme.tabAlignment', (WidgetTester tester) async {
final TabController controller1 = TabController(
length: 2,
vsync: const TestVSync(),
);
addTearDown(controller1.dispose);
/// Test non-scrollable tab bar.
await tester.pumpWidget(
MaterialApp(
......@@ -822,7 +878,7 @@ void main() {
appBar: AppBar(
bottom: TabBar(
tabAlignment: TabAlignment.center,
controller: TabController(length: 2, vsync: const TestVSync()),
controller: controller1,
tabs: const <Widget>[
Tab(text: 'Tab 1'),
Tab(text: 'Tab 3'),
......@@ -842,6 +898,12 @@ void main() {
double tabTwoRight = (availableWidth / 2) + tabTwoRect.width + kTabLabelPadding.right;
expect(tabTwoRect.right, equals(tabTwoRight));
final TabController controller2 = TabController(
length: 2,
vsync: const TestVSync(),
);
addTearDown(controller2.dispose);
/// Test scrollable tab bar.
await tester.pumpWidget(
MaterialApp(
......@@ -854,7 +916,7 @@ void main() {
bottom: TabBar(
isScrollable: true,
tabAlignment: TabAlignment.start,
controller: TabController(length: 2, vsync: const TestVSync()),
controller: controller2,
tabs: const <Widget>[
Tab(text: 'Tab 1'),
Tab(text: 'Tab 3'),
......@@ -875,7 +937,7 @@ void main() {
expect(tabTwoRect.right, equals(tabTwoRight));
});
testWidgets(
testWidgetsWithLeakTracking(
'TabBar labels use colors from TabBarTheme.labelStyle & TabBarTheme.unselectedLabelStyle',
(WidgetTester tester) async {
const TextStyle labelStyle = TextStyle(
......@@ -911,7 +973,7 @@ void main() {
expect(unselectedTextStyle.fontStyle, unselectedLabelStyle.fontStyle);
});
testWidgets(
testWidgetsWithLeakTracking(
"TabBarTheme's labelColor & unselectedLabelColor override labelStyle & unselectedLabelStyle colors",
(WidgetTester tester) async {
const Color labelColor = Color(0xfff00000);
......@@ -975,7 +1037,7 @@ void main() {
expect(unselectedTextStyle.fontStyle, unselectedLabelStyle.fontStyle);
});
testWidgets(
testWidgetsWithLeakTracking(
"TabBarTheme's labelColor & unselectedLabelColor override TabBar.labelStyle & TabBar.unselectedLabelStyle colors",
(WidgetTester tester) async {
const Color labelColor = Color(0xfff00000);
......@@ -1054,7 +1116,7 @@ void main() {
// support is deprecated and the APIs are removed, these tests
// can be deleted.
testWidgets('Tab bar defaults (primary)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar defaults (primary)', (WidgetTester tester) async {
// Test default label color and label styles.
await tester.pumpWidget(buildTabBar());
......@@ -1094,7 +1156,7 @@ void main() {
expect(tabBarBox, paints..line(color: theme.indicatorColor));
});
testWidgets('Tab bar defaults (secondary)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar defaults (secondary)', (WidgetTester tester) async {
// Test default label color and label styles.
await tester.pumpWidget(buildTabBar(secondaryTabBar: true));
......@@ -1134,7 +1196,7 @@ void main() {
expect(tabBarBox, paints..line(color: theme.indicatorColor));
});
testWidgets('Tab bar default tab indicator size', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tab bar default tab indicator size', (WidgetTester tester) async {
await tester.pumpWidget(buildTabBar());
await expectLater(
......@@ -1143,7 +1205,7 @@ void main() {
);
});
testWidgets('TabBarTheme.indicatorSize provides correct tab indicator (primary)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TabBarTheme.indicatorSize provides correct tab indicator (primary)', (WidgetTester tester) async {
final ThemeData theme = ThemeData(
tabBarTheme: const TabBarTheme(indicatorSize: TabBarIndicatorSize.tab),
useMaterial3: false,
......@@ -1156,6 +1218,7 @@ void main() {
vsync: const TestVSync(),
length: tabs.length,
);
addTearDown(controller.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -1193,7 +1256,7 @@ void main() {
);
});
testWidgets('TabBarTheme.indicatorSize provides correct tab indicator (secondary)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TabBarTheme.indicatorSize provides correct tab indicator (secondary)', (WidgetTester tester) async {
final ThemeData theme = ThemeData(
tabBarTheme: const TabBarTheme(indicatorSize: TabBarIndicatorSize.label),
useMaterial3: false,
......@@ -1206,6 +1269,7 @@ void main() {
vsync: const TestVSync(),
length: tabs.length,
);
addTearDown(controller.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -1241,7 +1305,13 @@ void main() {
);
});
testWidgets('TabBar respects TabBarTheme.tabAlignment', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TabBar respects TabBarTheme.tabAlignment', (WidgetTester tester) async {
final TabController controller = TabController(
length: 2,
vsync: const TestVSync(),
);
addTearDown(controller.dispose);
// Test non-scrollable tab bar.
await tester.pumpWidget(
MaterialApp(
......@@ -1252,7 +1322,7 @@ void main() {
home: Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: TabController(length: 2, vsync: const TestVSync()),
controller: controller,
tabs: const <Widget>[
Tab(text: 'Tab 1'),
Tab(text: 'Tab 3'),
......@@ -1272,7 +1342,13 @@ void main() {
expect(tabTwoRect.right, equals(tabTwoRight));
});
testWidgets('TabBar.tabAlignment overrides TabBarTheme.tabAlignment', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TabBar.tabAlignment overrides TabBarTheme.tabAlignment', (WidgetTester tester) async {
final TabController controller = TabController(
length: 2,
vsync: const TestVSync(),
);
addTearDown(controller.dispose);
// Test non-scrollable tab bar.
await tester.pumpWidget(
MaterialApp(
......@@ -1284,7 +1360,7 @@ void main() {
appBar: AppBar(
bottom: TabBar(
tabAlignment: TabAlignment.center,
controller: TabController(length: 2, vsync: const TestVSync()),
controller: controller,
tabs: const <Widget>[
Tab(text: 'Tab 1'),
Tab(text: 'Tab 3'),
......@@ -1305,7 +1381,7 @@ void main() {
});
});
testWidgets('Material3 - TabBar indicator respects TabBarTheme.indicatorColor', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Material3 - TabBar indicator respects TabBarTheme.indicatorColor', (WidgetTester tester) async {
final List<Widget> tabs = List<Widget>.generate(4, (int index) {
return Tab(text: 'Tab $index');
});
......@@ -1314,6 +1390,7 @@ void main() {
vsync: const TestVSync(),
length: tabs.length,
);
addTearDown(controller.dispose);
const Color tabBarThemeIndicatorColor = Color(0xffff0000);
......@@ -1347,7 +1424,7 @@ void main() {
expect(tabBarBox,paints..rrect(color: tabBarThemeIndicatorColor));
});
testWidgets('Material2 - TabBar indicator respects TabBarTheme.indicatorColor', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Material2 - TabBar indicator respects TabBarTheme.indicatorColor', (WidgetTester tester) async {
final List<Widget> tabs = List<Widget>.generate(4, (int index) {
return Tab(text: 'Tab $index');
});
......@@ -1356,6 +1433,7 @@ void main() {
vsync: const TestVSync(),
length: tabs.length,
);
addTearDown(controller.dispose);
const Color themeIndicatorColor = Color(0xffff0000);
const Color tabBarThemeIndicatorColor = Color(0xffffff00);
......@@ -1391,7 +1469,7 @@ void main() {
expect(tabBarBox,paints..line(color: tabBarThemeIndicatorColor));
});
testWidgets('TabBarTheme.labelColor resolves material states', (WidgetTester tester) async {
testWidgetsWithLeakTracking('TabBarTheme.labelColor resolves material states', (WidgetTester tester) async {
const Color selectedColor = Color(0xff00ff00);
const Color unselectedColor = Color(0xffff0000);
final MaterialStateColor labelColor = MaterialStateColor.resolveWith((Set<MaterialState> states) {
......@@ -1417,7 +1495,7 @@ void main() {
expect(unselectedTextStyle.color, unselectedColor);
});
testWidgets('TabBarTheme.labelColor & TabBarTheme.unselectedLabelColor override material state TabBarTheme.labelColor',
testWidgetsWithLeakTracking('TabBarTheme.labelColor & TabBarTheme.unselectedLabelColor override material state TabBarTheme.labelColor',
(WidgetTester tester) async {
const Color selectedStateColor = Color(0xff00ff00);
const Color unselectedStateColor = Color(0xffff0000);
......
......@@ -787,7 +787,7 @@ void main() {
expect(state.widget.cursorColor, cursorColor);
});
testWidgets('Use error cursor color when an InputDecoration with an errorText or error widget is provided', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Use error cursor color when an InputDecoration with an errorText or error widget is provided', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: Material(
......@@ -2484,7 +2484,7 @@ void main() {
expect(controller.selection.extentOffset, testValue.indexOf('g'));
});
testWidgets('Can move cursor when dragging, when tap is on collapsed selection (iOS)', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Can move cursor when dragging, when tap is on collapsed selection (iOS)', (WidgetTester tester) async {
final TextEditingController controller = _textEditingController();
await tester.pumpWidget(
......@@ -2527,6 +2527,11 @@ void main() {
expect(controller.selection.isCollapsed, true);
expect(controller.selection.baseOffset, testValue.indexOf('i'));
// End gesture and skip the magnifier hide animation, so it can release
// resources.
await gesture.up();
await tester.pumpAndSettle();
},
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }),
);
......@@ -2576,7 +2581,7 @@ void main() {
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }),
);
testWidgets('Can move cursor when dragging, when tap is on collapsed selection (iOS) - multiline', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Can move cursor when dragging, when tap is on collapsed selection (iOS) - multiline', (WidgetTester tester) async {
final TextEditingController controller = _textEditingController();
await tester.pumpWidget(
......@@ -2620,11 +2625,16 @@ void main() {
expect(controller.selection.isCollapsed, true);
expect(controller.selection.baseOffset, testValue.indexOf('i'));
// End gesture and skip the magnifier hide animation, so it can release
// resources.
await gesture.up();
await tester.pumpAndSettle();
},
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }),
);
testWidgets('Can move cursor when dragging, when tap is on collapsed selection (iOS) - ListView', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Can move cursor when dragging, when tap is on collapsed selection (iOS) - ListView', (WidgetTester tester) async {
// This is a regression test for
// https://github.com/flutter/flutter/issues/122519
final TextEditingController controller = _textEditingController();
......@@ -2697,6 +2707,11 @@ void main() {
expect(controller.selection.isCollapsed, true);
expect(controller.selection.baseOffset, testValue.indexOf('i'));
// End gesture and skip the magnifier hide animation, so it can release
// resources.
await gesture.up();
await tester.pumpAndSettle();
},
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }),
);
......@@ -12361,7 +12376,7 @@ void main() {
skip: isBrowser, // [intended] Browser handles arrow keys differently.
);
testWidgets('long press drag can edge scroll vertically', (WidgetTester tester) async {
testWidgetsWithLeakTracking('long press drag can edge scroll vertically', (WidgetTester tester) async {
final TextEditingController controller = _textEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neigse Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges',
);
......@@ -12438,6 +12453,11 @@ void main() {
textOffsetToPosition(tester, 0).dy,
moreOrLessEquals(firstCharY - lineHeight, epsilon: 1),
);
// End gesture and skip the magnifier hide animation, so it can release
// resources.
await gesture.up();
await tester.pumpAndSettle();
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgetsWithLeakTracking('keyboard selection change scrolls the field vertically', (WidgetTester tester) async {
......@@ -14283,7 +14303,7 @@ void main() {
});
});
});
testWidgets("Arrow keys don't move input focus", (WidgetTester tester) async {
testWidgetsWithLeakTracking("Arrow keys don't move input focus", (WidgetTester tester) async {
final TextEditingController controller1 = _textEditingController();
final TextEditingController controller2 = _textEditingController();
final TextEditingController controller3 = _textEditingController();
......@@ -14446,7 +14466,7 @@ void main() {
expect(textFieldSize1, equals(textFieldSize2));
});
testWidgets(
testWidgetsWithLeakTracking(
'The selection menu displays in an Overlay without error',
(WidgetTester tester) async {
// This is a regression test for
......@@ -14455,6 +14475,9 @@ void main() {
text: 'This is a test that shows some odd behavior with Text Selection!',
);
late final OverlayEntry overlayEntry;
addTearDown(() => overlayEntry..remove()..dispose());
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: ColoredBox(
......@@ -14466,7 +14489,7 @@ void main() {
height: 600,
child: Overlay(
initialEntries: <OverlayEntry>[
OverlayEntry(
overlayEntry = OverlayEntry(
builder: (BuildContext context) => Center(
child: TextField(
controller: controller,
......@@ -16271,7 +16294,7 @@ void main() {
});
group('magnifier builder', () {
testWidgets('should build custom magnifier if given',
testWidgetsWithLeakTracking('should build custom magnifier if given',
(WidgetTester tester) async {
final Widget customMagnifier = Container(
key: UniqueKey(),
......@@ -16286,14 +16309,15 @@ void main() {
home: Placeholder(),
));
final BuildContext context =
tester.firstElement(find.byType(Placeholder));
final BuildContext context = tester.firstElement(find.byType(Placeholder));
final ValueNotifier<MagnifierInfo> magnifierInfo = ValueNotifier<MagnifierInfo>(MagnifierInfo.empty);
addTearDown(magnifierInfo.dispose);
expect(
textField.magnifierConfiguration!.magnifierBuilder(
context,
MagnifierController(),
ValueNotifier<MagnifierInfo>(MagnifierInfo.empty),
magnifierInfo,
),
isA<Widget>().having(
(Widget widget) => widget.key,
......@@ -16302,24 +16326,26 @@ void main() {
});
group('defaults', () {
testWidgets('should build Magnifier on Android', (WidgetTester tester) async {
testWidgetsWithLeakTracking('should build Magnifier on Android', (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(
home: Scaffold(body: TextField()))
);
final BuildContext context = tester.firstElement(find.byType(TextField));
final EditableText editableText = tester.widget(find.byType(EditableText));
final ValueNotifier<MagnifierInfo> magnifierInfo = ValueNotifier<MagnifierInfo>(MagnifierInfo.empty);
addTearDown(magnifierInfo.dispose);
expect(
editableText.magnifierConfiguration.magnifierBuilder(
context,
MagnifierController(),
ValueNotifier<MagnifierInfo>(MagnifierInfo.empty),
magnifierInfo,
),
isA<TextMagnifier>());
}, variant: TargetPlatformVariant.only(TargetPlatform.android));
testWidgets('should build CupertinoMagnifier on iOS',
testWidgetsWithLeakTracking('should build CupertinoMagnifier on iOS',
(WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(
home: Scaffold(body: TextField()))
......@@ -16327,17 +16353,19 @@ void main() {
final BuildContext context = tester.firstElement(find.byType(TextField));
final EditableText editableText = tester.widget(find.byType(EditableText));
final ValueNotifier<MagnifierInfo> magnifierInfo = ValueNotifier<MagnifierInfo>(MagnifierInfo.empty);
addTearDown(magnifierInfo.dispose);
expect(
editableText.magnifierConfiguration.magnifierBuilder(
context,
MagnifierController(),
ValueNotifier<MagnifierInfo>(MagnifierInfo.empty),
magnifierInfo,
),
isA<CupertinoTextMagnifier>());
}, variant: TargetPlatformVariant.only(TargetPlatform.iOS));
testWidgets('should build nothing on Android and iOS',
testWidgetsWithLeakTracking('should build nothing on Android and iOS',
(WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(
home: Scaffold(body: TextField()))
......@@ -16345,12 +16373,14 @@ void main() {
final BuildContext context = tester.firstElement(find.byType(TextField));
final EditableText editableText = tester.widget(find.byType(EditableText));
final ValueNotifier<MagnifierInfo> magnifierInfo = ValueNotifier<MagnifierInfo>(MagnifierInfo.empty);
addTearDown(magnifierInfo.dispose);
expect(
editableText.magnifierConfiguration.magnifierBuilder(
context,
MagnifierController(),
ValueNotifier<MagnifierInfo>(MagnifierInfo.empty),
magnifierInfo,
),
isNull);
},
......
......@@ -694,7 +694,7 @@ void main() {
expect(find.text('5 of 10'), findsOneWidget);
});
testWidgets('readonly text form field will hide cursor by default', (WidgetTester tester) async {
testWidgetsWithLeakTracking('readonly text form field will hide cursor by default', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Material(
......
......@@ -864,12 +864,15 @@ void main() {
expect(tooltipContainer.padding, const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0));
}, variant: const TargetPlatformVariant(<TargetPlatform>{TargetPlatform.macOS, TargetPlatform.linux, TargetPlatform.windows}));
testWidgets('Can tooltip decoration be customized', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Can tooltip decoration be customized', (WidgetTester tester) async {
final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
const Decoration customDecoration = ShapeDecoration(
shape: StadiumBorder(),
color: Color(0x80800000),
);
late final OverlayEntry entry;
addTearDown(() => entry..remove()..dispose());
await tester.pumpWidget(
Theme(
data: ThemeData(useMaterial3: false),
......@@ -877,7 +880,7 @@ void main() {
textDirection: TextDirection.ltr,
child: Overlay(
initialEntries: <OverlayEntry>[
OverlayEntry(
entry = OverlayEntry(
builder: (BuildContext context) {
return Tooltip(
key: tooltipKey,
......@@ -1422,16 +1425,18 @@ void main() {
await tester.pump(waitDuration);
});
testWidgets('Does tooltip contribute semantics', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Does tooltip contribute semantics', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
final GlobalKey<TooltipState> tooltipKey = GlobalKey<TooltipState>();
late final OverlayEntry entry;
addTearDown(() => entry..remove()..dispose());
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: Overlay(
initialEntries: <OverlayEntry>[
OverlayEntry(
entry = OverlayEntry(
builder: (BuildContext context) {
return Stack(
children: <Widget>[
......@@ -2349,7 +2354,7 @@ void main() {
expect(tester.takeException(), isNull);
});
testWidgets('Tooltip is not selectable', (WidgetTester tester) async {
testWidgetsWithLeakTracking('Tooltip is not selectable', (WidgetTester tester) async {
const String tooltipText = 'AAAAAAAAAAAAAAAAAAAAAAA';
String? selectedText;
await tester.pumpWidget(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment