1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'package:flutter/material.dart'; |
6 | import 'package:flutter_test/flutter_test.dart'; |
7 | |
8 | void main() { |
9 | test('ButtonThemeData defaults' , () { |
10 | const ButtonThemeData theme = ButtonThemeData(); |
11 | expect(theme.textTheme, ButtonTextTheme.normal); |
12 | expect(theme.constraints, const BoxConstraints(minWidth: 88.0, minHeight: 36.0)); |
13 | expect(theme.padding, const EdgeInsets.symmetric(horizontal: 16.0)); |
14 | expect( |
15 | theme.shape, |
16 | const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0))), |
17 | ); |
18 | expect(theme.alignedDropdown, false); |
19 | expect(theme.layoutBehavior, ButtonBarLayoutBehavior.padded); |
20 | }); |
21 | |
22 | test('ButtonThemeData default overrides' , () { |
23 | const ButtonThemeData theme = ButtonThemeData( |
24 | textTheme: ButtonTextTheme.primary, |
25 | minWidth: 100.0, |
26 | height: 200.0, |
27 | padding: EdgeInsets.zero, |
28 | shape: RoundedRectangleBorder(), |
29 | alignedDropdown: true, |
30 | ); |
31 | expect(theme.textTheme, ButtonTextTheme.primary); |
32 | expect(theme.constraints, const BoxConstraints(minWidth: 100.0, minHeight: 200.0)); |
33 | expect(theme.padding, EdgeInsets.zero); |
34 | expect(theme.shape, const RoundedRectangleBorder()); |
35 | expect(theme.alignedDropdown, true); |
36 | }); |
37 | |
38 | test('ButtonThemeData.copyWith' , () { |
39 | ButtonThemeData theme = const ButtonThemeData().copyWith(); |
40 | expect(theme.textTheme, ButtonTextTheme.normal); |
41 | expect(theme.layoutBehavior, ButtonBarLayoutBehavior.padded); |
42 | expect(theme.constraints, const BoxConstraints(minWidth: 88.0, minHeight: 36.0)); |
43 | expect(theme.padding, const EdgeInsets.symmetric(horizontal: 16.0)); |
44 | expect( |
45 | theme.shape, |
46 | const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0))), |
47 | ); |
48 | expect(theme.alignedDropdown, false); |
49 | expect(theme.colorScheme, null); |
50 | |
51 | theme = const ButtonThemeData().copyWith( |
52 | textTheme: ButtonTextTheme.primary, |
53 | layoutBehavior: ButtonBarLayoutBehavior.constrained, |
54 | minWidth: 100.0, |
55 | height: 200.0, |
56 | padding: EdgeInsets.zero, |
57 | shape: const StadiumBorder(), |
58 | alignedDropdown: true, |
59 | colorScheme: const ColorScheme.dark(), |
60 | materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, |
61 | ); |
62 | expect(theme.textTheme, ButtonTextTheme.primary); |
63 | expect(theme.layoutBehavior, ButtonBarLayoutBehavior.constrained); |
64 | expect(theme.constraints, const BoxConstraints(minWidth: 100.0, minHeight: 200.0)); |
65 | expect(theme.padding, EdgeInsets.zero); |
66 | expect(theme.shape, const StadiumBorder()); |
67 | expect(theme.alignedDropdown, true); |
68 | expect(theme.colorScheme, const ColorScheme.dark()); |
69 | }); |
70 | |
71 | testWidgets('ButtonTheme alignedDropdown' , (WidgetTester tester) async { |
72 | final Key dropdownKey = UniqueKey(); |
73 | |
74 | Widget buildFrame({required bool alignedDropdown, required TextDirection textDirection}) { |
75 | return MaterialApp( |
76 | builder: (BuildContext context, Widget? child) { |
77 | return Directionality(textDirection: textDirection, child: child!); |
78 | }, |
79 | home: ButtonTheme( |
80 | alignedDropdown: alignedDropdown, |
81 | child: Material( |
82 | child: Builder( |
83 | builder: (BuildContext context) { |
84 | return Container( |
85 | alignment: Alignment.center, |
86 | child: DropdownButtonHideUnderline( |
87 | child: SizedBox( |
88 | width: 200.0, |
89 | child: DropdownButton<String>( |
90 | key: dropdownKey, |
91 | onChanged: (String? value) {}, |
92 | value: 'foo' , |
93 | items: const <DropdownMenuItem<String>>[ |
94 | DropdownMenuItem<String>(value: 'foo' , child: Text('foo' )), |
95 | DropdownMenuItem<String>(value: 'bar' , child: Text('bar' )), |
96 | ], |
97 | ), |
98 | ), |
99 | ), |
100 | ); |
101 | }, |
102 | ), |
103 | ), |
104 | ), |
105 | ); |
106 | } |
107 | |
108 | final Finder button = find.byKey(dropdownKey); |
109 | final Finder menu = find.byWidgetPredicate( |
110 | (Widget w) => ' ${w.runtimeType}' == '_DropdownMenu<String>' , |
111 | ); |
112 | |
113 | await tester.pumpWidget(buildFrame(alignedDropdown: false, textDirection: TextDirection.ltr)); |
114 | await tester.tap(button); |
115 | await tester.pumpAndSettle(); |
116 | |
117 | // 240 = 200.0 (button width) + _kUnalignedMenuMargin (20.0 left and right) |
118 | expect(tester.getSize(button).width, 200.0); |
119 | expect(tester.getSize(menu).width, 240.0); |
120 | |
121 | // Dismiss the menu. |
122 | await tester.tapAt(Offset.zero); |
123 | await tester.pumpAndSettle(); |
124 | expect(menu, findsNothing); |
125 | |
126 | await tester.pumpWidget(buildFrame(alignedDropdown: true, textDirection: TextDirection.ltr)); |
127 | await tester.tap(button); |
128 | await tester.pumpAndSettle(); |
129 | |
130 | // Aligneddropdown: true means the button and menu widths match |
131 | expect(tester.getSize(button).width, 200.0); |
132 | expect(tester.getSize(menu).width, 200.0); |
133 | |
134 | // There are two 'foo' widgets: the selected menu item's label and the drop |
135 | // down button's label. The should both appear at the same location. |
136 | final Finder fooText = find.text('foo' ); |
137 | expect(fooText, findsNWidgets(2)); |
138 | expect(tester.getRect(fooText.at(0)), tester.getRect(fooText.at(1))); |
139 | |
140 | // Dismiss the menu. |
141 | await tester.tapAt(Offset.zero); |
142 | await tester.pumpAndSettle(); |
143 | expect(menu, findsNothing); |
144 | |
145 | // Same test as above except RTL |
146 | await tester.pumpWidget(buildFrame(alignedDropdown: true, textDirection: TextDirection.rtl)); |
147 | await tester.tap(button); |
148 | await tester.pumpAndSettle(); |
149 | |
150 | expect(fooText, findsNWidgets(2)); |
151 | expect(tester.getRect(fooText.at(0)), tester.getRect(fooText.at(1))); |
152 | }); |
153 | } |
154 | |