| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/gestures.dart'; |
| import 'package:flutter/material.dart'; |
| import 'package:flutter/rendering.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| import '../foundation/leak_tracking.dart'; |
| import '../rendering/mock_canvas.dart'; |
| |
| Widget boilerplate({required Widget child}) { |
| return Directionality( |
| textDirection: TextDirection.ltr, |
| child: Center(child: child), |
| ); |
| } |
| |
| void main() { |
| test('ToggleButtonsThemeData copyWith, ==, hashCode basics', () { |
| expect(const ToggleButtonsThemeData(), const ToggleButtonsThemeData().copyWith()); |
| expect(const ToggleButtonsThemeData().hashCode, const ToggleButtonsThemeData().copyWith().hashCode); |
| }); |
| |
| test('ToggleButtonsThemeData lerp special cases', () { |
| expect(ToggleButtonsThemeData.lerp(null, null, 0), null); |
| const ToggleButtonsThemeData data = ToggleButtonsThemeData(); |
| expect(identical(ToggleButtonsThemeData.lerp(data, data, 0.5), data), true); |
| }); |
| |
| test('ToggleButtonsThemeData defaults', () { |
| const ToggleButtonsThemeData themeData = ToggleButtonsThemeData(); |
| expect(themeData.textStyle, null); |
| expect(themeData.constraints, null); |
| expect(themeData.color, null); |
| expect(themeData.selectedColor, null); |
| expect(themeData.disabledColor, null); |
| expect(themeData.fillColor, null); |
| expect(themeData.focusColor, null); |
| expect(themeData.highlightColor, null); |
| expect(themeData.hoverColor, null); |
| expect(themeData.splashColor, null); |
| expect(themeData.borderColor, null); |
| expect(themeData.selectedBorderColor, null); |
| expect(themeData.disabledBorderColor, null); |
| expect(themeData.borderRadius, null); |
| expect(themeData.borderWidth, null); |
| |
| const ToggleButtonsTheme theme = ToggleButtonsTheme(data: ToggleButtonsThemeData(), child: SizedBox()); |
| expect(theme.data.textStyle, null); |
| expect(theme.data.constraints, null); |
| expect(theme.data.color, null); |
| expect(theme.data.selectedColor, null); |
| expect(theme.data.disabledColor, null); |
| expect(theme.data.fillColor, null); |
| expect(theme.data.focusColor, null); |
| expect(theme.data.highlightColor, null); |
| expect(theme.data.hoverColor, null); |
| expect(theme.data.splashColor, null); |
| expect(theme.data.borderColor, null); |
| expect(theme.data.selectedBorderColor, null); |
| expect(theme.data.disabledBorderColor, null); |
| expect(theme.data.borderRadius, null); |
| expect(theme.data.borderWidth, null); |
| }); |
| |
| testWidgetsWithLeakTracking('Default ToggleButtonsThemeData debugFillProperties', (WidgetTester tester) async { |
| final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); |
| const ToggleButtonsThemeData().debugFillProperties(builder); |
| |
| final List<String> description = builder.properties |
| .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) |
| .map((DiagnosticsNode node) => node.toString()) |
| .toList(); |
| |
| expect(description, <String>[]); |
| }); |
| |
| testWidgetsWithLeakTracking('ToggleButtonsThemeData implements debugFillProperties', (WidgetTester tester) async { |
| final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); |
| const ToggleButtonsThemeData( |
| textStyle: TextStyle(fontSize: 10), |
| constraints: BoxConstraints(minHeight: 10.0, maxHeight: 20.0), |
| color: Color(0xfffffff0), |
| selectedColor: Color(0xfffffff1), |
| disabledColor: Color(0xfffffff2), |
| fillColor: Color(0xfffffff3), |
| focusColor: Color(0xfffffff4), |
| highlightColor: Color(0xfffffff5), |
| hoverColor: Color(0xfffffff6), |
| splashColor: Color(0xfffffff7), |
| borderColor: Color(0xfffffff8), |
| selectedBorderColor: Color(0xfffffff9), |
| disabledBorderColor: Color(0xfffffffa), |
| borderRadius: BorderRadius.all(Radius.circular(4.0)), |
| borderWidth: 2.0, |
| ).debugFillProperties(builder); |
| |
| final List<String> description = builder.properties |
| .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) |
| .map((DiagnosticsNode node) => node.toString()) |
| .toList(); |
| |
| expect(description, <String>[ |
| 'textStyle.inherit: true', |
| 'textStyle.size: 10.0', |
| 'constraints: BoxConstraints(0.0<=w<=Infinity, 10.0<=h<=20.0)', |
| 'color: Color(0xfffffff0)', |
| 'selectedColor: Color(0xfffffff1)', |
| 'disabledColor: Color(0xfffffff2)', |
| 'fillColor: Color(0xfffffff3)', |
| 'focusColor: Color(0xfffffff4)', |
| 'highlightColor: Color(0xfffffff5)', |
| 'hoverColor: Color(0xfffffff6)', |
| 'splashColor: Color(0xfffffff7)', |
| 'borderColor: Color(0xfffffff8)', |
| 'selectedBorderColor: Color(0xfffffff9)', |
| 'disabledBorderColor: Color(0xfffffffa)', |
| 'borderRadius: BorderRadius.circular(4.0)', |
| 'borderWidth: 2.0', |
| ]); |
| }); |
| |
| testWidgetsWithLeakTracking('Theme text style, except color, is applied', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: const ToggleButtonsThemeData( |
| textStyle: TextStyle( |
| color: Colors.orange, |
| textBaseline: TextBaseline.ideographic, |
| fontSize: 20.0, |
| ), |
| ), |
| child: ToggleButtons( |
| isSelected: const <bool>[false, true], |
| onPressed: (int index) {}, |
| children: const <Widget>[ |
| Text('First child'), |
| Text('Second child'), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| TextStyle textStyle; |
| textStyle = tester.widget<DefaultTextStyle>(find.descendant( |
| of: find.widgetWithText(TextButton, 'First child'), |
| matching: find.byType(DefaultTextStyle), |
| )).style; |
| expect(textStyle.textBaseline, TextBaseline.ideographic); |
| expect(textStyle.fontSize, 20.0); |
| expect(textStyle.color, isNot(Colors.orange)); |
| |
| textStyle = tester.widget<DefaultTextStyle>(find.descendant( |
| of: find.widgetWithText(TextButton, 'Second child'), |
| matching: find.byType(DefaultTextStyle), |
| )).style; |
| expect(textStyle.textBaseline, TextBaseline.ideographic); |
| expect(textStyle.fontSize, 20.0); |
| expect(textStyle.color, isNot(Colors.orange)); |
| }); |
| |
| testWidgetsWithLeakTracking('Custom BoxConstraints', (WidgetTester tester) async { |
| // Test for minimum constraints |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: const ToggleButtonsThemeData( |
| constraints: BoxConstraints( |
| minWidth: 50.0, |
| minHeight: 60.0, |
| ), |
| ), |
| child: ToggleButtons( |
| tapTargetSize: MaterialTapTargetSize.shrinkWrap, |
| isSelected: const <bool>[false, false, false], |
| onPressed: (int index) {}, |
| children: const <Widget>[ |
| Icon(Icons.check), |
| Icon(Icons.access_alarm), |
| Icon(Icons.cake), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| Rect firstRect = tester.getRect(find.byType(TextButton).at(0)); |
| expect(firstRect.width, 50.0); |
| expect(firstRect.height, 60.0); |
| Rect secondRect = tester.getRect(find.byType(TextButton).at(1)); |
| expect(secondRect.width, 50.0); |
| expect(secondRect.height, 60.0); |
| Rect thirdRect = tester.getRect(find.byType(TextButton).at(2)); |
| expect(thirdRect.width, 50.0); |
| expect(thirdRect.height, 60.0); |
| |
| // Test for maximum constraints |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: const ToggleButtonsThemeData( |
| constraints: BoxConstraints( |
| maxWidth: 20.0, |
| maxHeight: 10.0, |
| ), |
| ), |
| child: ToggleButtons( |
| tapTargetSize: MaterialTapTargetSize.shrinkWrap, |
| isSelected: const <bool>[false, false, false], |
| onPressed: (int index) {}, |
| children: const <Widget>[ |
| Icon(Icons.check), |
| Icon(Icons.access_alarm), |
| Icon(Icons.cake), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| firstRect = tester.getRect(find.byType(TextButton).at(0)); |
| expect(firstRect.width, 20.0); |
| expect(firstRect.height, 10.0); |
| secondRect = tester.getRect(find.byType(TextButton).at(1)); |
| expect(secondRect.width, 20.0); |
| expect(secondRect.height, 10.0); |
| thirdRect = tester.getRect(find.byType(TextButton).at(2)); |
| expect(thirdRect.width, 20.0); |
| expect(thirdRect.height, 10.0); |
| }); |
| |
| testWidgetsWithLeakTracking( |
| 'Theme text/icon colors for enabled, selected and disabled states', |
| (WidgetTester tester) async { |
| TextStyle buttonTextStyle(String text) { |
| return tester.widget<DefaultTextStyle>(find.descendant( |
| of: find.widgetWithText(TextButton, text), |
| matching: find.byType(DefaultTextStyle), |
| )).style; |
| } |
| IconTheme iconTheme(IconData icon) { |
| return tester.widget(find.descendant( |
| of: find.widgetWithIcon(TextButton, icon), |
| matching: find.byType(IconTheme), |
| )); |
| } |
| final ThemeData theme = ThemeData(); |
| const Color enabledColor = Colors.lime; |
| const Color selectedColor = Colors.green; |
| const Color disabledColor = Colors.yellow; |
| |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: const ToggleButtonsThemeData(), |
| child: ToggleButtons( |
| color: enabledColor, |
| isSelected: const <bool>[false], |
| onPressed: (int index) {}, |
| children: const <Widget>[ |
| // This Row is used like this to test for both TextStyle |
| // and IconTheme for Text and Icon widgets respectively. |
| Row(children: <Widget>[ |
| Text('First child'), |
| Icon(Icons.check), |
| ]), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| // Custom theme enabled color |
| expect(theme.colorScheme.onSurface, isNot(enabledColor)); |
| expect(buttonTextStyle('First child').color, enabledColor); |
| expect(iconTheme(Icons.check).data.color, enabledColor); |
| |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: const ToggleButtonsThemeData( |
| selectedColor: selectedColor, |
| ), |
| child: ToggleButtons( |
| color: enabledColor, |
| isSelected: const <bool>[true], |
| onPressed: (int index) {}, |
| children: const <Widget>[ |
| Row(children: <Widget>[ |
| Text('First child'), |
| Icon(Icons.check), |
| ]), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| await tester.pumpAndSettle(); |
| // Custom theme selected color |
| expect(theme.colorScheme.primary, isNot(selectedColor)); |
| expect(buttonTextStyle('First child').color, selectedColor); |
| expect(iconTheme(Icons.check).data.color, selectedColor); |
| |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: const ToggleButtonsThemeData( |
| disabledColor: disabledColor, |
| ), |
| child: ToggleButtons( |
| color: enabledColor, |
| isSelected: const <bool>[false], |
| children: const <Widget>[ |
| Row(children: <Widget>[ |
| Text('First child'), |
| Icon(Icons.check), |
| ]), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| await tester.pumpAndSettle(); |
| // Custom theme disabled color |
| expect(theme.disabledColor, isNot(disabledColor)); |
| expect(buttonTextStyle('First child').color, disabledColor); |
| expect(iconTheme(Icons.check).data.color, disabledColor); |
| }, |
| ); |
| |
| testWidgetsWithLeakTracking('Theme button fillColor', (WidgetTester tester) async { |
| const Color customFillColor = Colors.green; |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: const ToggleButtonsThemeData(fillColor: customFillColor), |
| child: ToggleButtons( |
| isSelected: const <bool>[true], |
| onPressed: (int index) {}, |
| children: const <Widget>[ |
| Row(children: <Widget>[ |
| Text('First child'), |
| ]), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| final Material material = tester.widget<Material>(find.descendant( |
| of: find.byType(TextButton), |
| matching: find.byType(Material), |
| )); |
| expect(material.color, customFillColor); |
| expect(material.type, MaterialType.button); |
| }); |
| |
| testWidgetsWithLeakTracking('Custom Theme button fillColor in different states', (WidgetTester tester) async { |
| Material buttonColor(String text) { |
| return tester.widget<Material>( |
| find.descendant( |
| of: find.byType(TextButton), |
| matching: find.widgetWithText(Material, text), |
| ), |
| ); |
| } |
| |
| const Color enabledFillColor = Colors.green; |
| const Color selectedFillColor = Colors.blue; |
| const Color disabledFillColor = Colors.yellow; |
| |
| Color getColor(Set<MaterialState> states) { |
| if (states.contains(MaterialState.selected)) { |
| return selectedFillColor; |
| } else if (states.contains(MaterialState.disabled)) { |
| return disabledFillColor; |
| } |
| return enabledFillColor; |
| } |
| |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: ToggleButtonsThemeData(fillColor: MaterialStateColor.resolveWith(getColor)), |
| child: ToggleButtons( |
| isSelected: const <bool>[true, false], |
| onPressed: (int index) {}, |
| children: const <Widget> [ |
| Text('First child'), |
| Text('Second child'), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| await tester.pumpAndSettle(); |
| |
| expect(buttonColor('First child').color, selectedFillColor); |
| expect(buttonColor('Second child').color, enabledFillColor); |
| |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: ToggleButtonsThemeData(fillColor: MaterialStateColor.resolveWith(getColor)), |
| child: ToggleButtons( |
| isSelected: const <bool>[true, false], |
| children: const <Widget>[ |
| Text('First child'), |
| Text('Second child'), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(buttonColor('First child').color, disabledFillColor); |
| expect(buttonColor('Second child').color, disabledFillColor); |
| }); |
| |
| testWidgetsWithLeakTracking('Theme InkWell colors', (WidgetTester tester) async { |
| const Color splashColor = Color(0xff4caf50); |
| const Color highlightColor = Color(0xffcddc39); |
| const Color hoverColor = Color(0xffffeb3b); |
| const Color focusColor = Color(0xffffff00); |
| final FocusNode focusNode = FocusNode(); |
| |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: const ToggleButtonsThemeData( |
| splashColor: splashColor, |
| highlightColor: highlightColor, |
| hoverColor: hoverColor, |
| focusColor: focusColor, |
| ), |
| child: ToggleButtons( |
| isSelected: const <bool>[true], |
| onPressed: (int index) {}, |
| focusNodes: <FocusNode>[focusNode], |
| children: const <Widget>[ |
| Text('First child'), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| final Offset center = tester.getCenter(find.text('First child')); |
| |
| // splashColor |
| // highlightColor |
| final TestGesture touchGesture = await tester.createGesture(); |
| await touchGesture.down(center); |
| await tester.pumpAndSettle(); |
| |
| RenderObject inkFeatures; |
| inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) { |
| return object.runtimeType.toString() == '_RenderInkFeatures'; |
| }); |
| expect( |
| inkFeatures, |
| paints |
| ..circle(color: splashColor) |
| ); |
| |
| await touchGesture.up(); |
| await tester.pumpAndSettle(); |
| |
| // hoverColor |
| final TestGesture hoverGesture = await tester.createGesture( |
| kind: PointerDeviceKind.mouse, |
| ); |
| await hoverGesture.addPointer(); |
| await hoverGesture.moveTo(center); |
| await tester.pumpAndSettle(); |
| |
| inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) { |
| return object.runtimeType.toString() == '_RenderInkFeatures'; |
| }); |
| expect(inkFeatures, paints..rect(color: hoverColor)); |
| await hoverGesture.moveTo(Offset.zero); |
| |
| // focusColor |
| focusNode.requestFocus(); |
| await tester.pumpAndSettle(); |
| inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) { |
| return object.runtimeType.toString() == '_RenderInkFeatures'; |
| }); |
| expect(inkFeatures, paints..rect(color: focusColor)); |
| |
| await hoverGesture.removePointer(); |
| }); |
| |
| testWidgetsWithLeakTracking( |
| 'Theme border width and border colors for enabled, selected and disabled states', |
| (WidgetTester tester) async { |
| const Color borderColor = Color(0xff4caf50); |
| const Color selectedBorderColor = Color(0xffcddc39); |
| const Color disabledBorderColor = Color(0xffffeb3b); |
| const double customWidth = 2.0; |
| |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: const ToggleButtonsThemeData( |
| borderColor: borderColor, |
| borderWidth: customWidth, |
| ), |
| child: ToggleButtons( |
| isSelected: const <bool>[false], |
| onPressed: (int index) {}, |
| children: const <Widget>[ |
| Text('First child'), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| RenderObject toggleButtonRenderObject; |
| toggleButtonRenderObject = tester.allRenderObjects.firstWhere((RenderObject object) { |
| return object.runtimeType.toString() == '_SelectToggleButtonRenderObject'; |
| }); |
| expect( |
| toggleButtonRenderObject, |
| paints |
| // physical model layer paint |
| ..path() |
| ..path( |
| style: PaintingStyle.stroke, |
| color: borderColor, |
| strokeWidth: customWidth, |
| ), |
| ); |
| |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: const ToggleButtonsThemeData( |
| selectedBorderColor: selectedBorderColor, |
| borderWidth: customWidth, |
| ), |
| child: ToggleButtons( |
| isSelected: const <bool>[true], |
| onPressed: (int index) {}, |
| children: const <Widget>[ |
| Text('First child'), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| toggleButtonRenderObject = tester.allRenderObjects.firstWhere((RenderObject object) { |
| return object.runtimeType.toString() == '_SelectToggleButtonRenderObject'; |
| }); |
| expect( |
| toggleButtonRenderObject, |
| paints |
| // physical model layer paint |
| ..path() |
| ..path( |
| style: PaintingStyle.stroke, |
| color: selectedBorderColor, |
| strokeWidth: customWidth, |
| ), |
| ); |
| |
| await tester.pumpWidget( |
| Material( |
| child: boilerplate( |
| child: ToggleButtonsTheme( |
| data: const ToggleButtonsThemeData( |
| disabledBorderColor: disabledBorderColor, |
| borderWidth: customWidth, |
| ), |
| child: ToggleButtons( |
| isSelected: const <bool>[false], |
| children: const <Widget>[ |
| Text('First child'), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| toggleButtonRenderObject = tester.allRenderObjects.firstWhere((RenderObject object) { |
| return object.runtimeType.toString() == '_SelectToggleButtonRenderObject'; |
| }); |
| expect( |
| toggleButtonRenderObject, |
| paints |
| // physical model layer paint |
| ..path() |
| ..path( |
| style: PaintingStyle.stroke, |
| color: disabledBorderColor, |
| strokeWidth: customWidth, |
| ), |
| ); |
| }, |
| ); |
| } |