| // Copyright 2015 The Chromium 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/widgets.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| import '../rendering/mock_canvas.dart'; |
| import '../widgets/semantics_tester.dart'; |
| |
| void main() { |
| setUp(() { |
| debugResetSemanticsIdCounter(); |
| }); |
| |
| testWidgets('FlatButton defaults', (WidgetTester tester) async { |
| final Finder rawButtonMaterial = find.descendant( |
| of: find.byType(FlatButton), |
| matching: find.byType(Material), |
| ); |
| |
| // Enabled FlatButton |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: FlatButton( |
| onPressed: () { }, |
| child: const Text('button'), |
| ), |
| ), |
| ); |
| Material material = tester.widget<Material>(rawButtonMaterial); |
| expect(material.animationDuration, const Duration(milliseconds: 200)); |
| expect(material.borderOnForeground, true); |
| expect(material.borderRadius, null); |
| expect(material.clipBehavior, Clip.none); |
| expect(material.color, null); |
| expect(material.elevation, 0.0); |
| expect(material.shadowColor, const Color(0xff000000)); |
| expect(material.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(2.0))); |
| expect(material.textStyle.color, const Color(0xdd000000)); |
| expect(material.textStyle.fontFamily, 'Roboto'); |
| expect(material.textStyle.fontSize, 14); |
| expect(material.textStyle.fontWeight, FontWeight.w500); |
| expect(material.type, MaterialType.transparency); |
| |
| final Offset center = tester.getCenter(find.byType(FlatButton)); |
| await tester.startGesture(center); |
| await tester.pumpAndSettle(); |
| |
| material = tester.widget<Material>(rawButtonMaterial); |
| // No change vs enabled and not pressed. |
| expect(material.animationDuration, const Duration(milliseconds: 200)); |
| expect(material.borderOnForeground, true); |
| expect(material.borderRadius, null); |
| expect(material.clipBehavior, Clip.none); |
| expect(material.color, null); |
| expect(material.elevation, 0.0); |
| expect(material.shadowColor, const Color(0xff000000)); |
| expect(material.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(2.0))); |
| expect(material.textStyle.color, const Color(0xdd000000)); |
| expect(material.textStyle.fontFamily, 'Roboto'); |
| expect(material.textStyle.fontSize, 14); |
| expect(material.textStyle.fontWeight, FontWeight.w500); |
| expect(material.type, MaterialType.transparency); |
| |
| // Disabled FlatButton |
| await tester.pumpWidget( |
| const Directionality( |
| textDirection: TextDirection.ltr, |
| child: FlatButton( |
| onPressed: null, |
| child: Text('button'), |
| ), |
| ), |
| ); |
| material = tester.widget<Material>(rawButtonMaterial); |
| expect(material.animationDuration, const Duration(milliseconds: 200)); |
| expect(material.borderOnForeground, true); |
| expect(material.borderRadius, null); |
| expect(material.clipBehavior, Clip.none); |
| expect(material.color, null); |
| expect(material.elevation, 0.0); |
| expect(material.shadowColor, const Color(0xff000000)); |
| expect(material.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(2.0))); |
| expect(material.textStyle.color, const Color(0x61000000)); |
| expect(material.textStyle.fontFamily, 'Roboto'); |
| expect(material.textStyle.fontSize, 14); |
| expect(material.textStyle.fontWeight, FontWeight.w500); |
| expect(material.type, MaterialType.transparency); |
| }); |
| |
| testWidgets('RaisedButton defaults', (WidgetTester tester) async { |
| final Finder rawButtonMaterial = find.descendant( |
| of: find.byType(RaisedButton), |
| matching: find.byType(Material), |
| ); |
| |
| // Enabled RaisedButton |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: RaisedButton( |
| onPressed: () { }, |
| child: const Text('button'), |
| ), |
| ), |
| ); |
| Material material = tester.widget<Material>(rawButtonMaterial); |
| expect(material.animationDuration, const Duration(milliseconds: 200)); |
| expect(material.borderOnForeground, true); |
| expect(material.borderRadius, null); |
| expect(material.clipBehavior, Clip.none); |
| expect(material.color, const Color(0xffe0e0e0)); |
| expect(material.elevation, 2.0); |
| expect(material.shadowColor, const Color(0xff000000)); |
| expect(material.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(2.0))); |
| expect(material.textStyle.color, const Color(0xdd000000)); |
| expect(material.textStyle.fontFamily, 'Roboto'); |
| expect(material.textStyle.fontSize, 14); |
| expect(material.textStyle.fontWeight, FontWeight.w500); |
| expect(material.type, MaterialType.button); |
| |
| final Offset center = tester.getCenter(find.byType(RaisedButton)); |
| await tester.startGesture(center); |
| await tester.pumpAndSettle(); |
| |
| // Only elevation changes when enabled and pressed. |
| material = tester.widget<Material>(rawButtonMaterial); |
| expect(material.animationDuration, const Duration(milliseconds: 200)); |
| expect(material.borderOnForeground, true); |
| expect(material.borderRadius, null); |
| expect(material.clipBehavior, Clip.none); |
| expect(material.color, const Color(0xffe0e0e0)); |
| expect(material.elevation, 8.0); |
| expect(material.shadowColor, const Color(0xff000000)); |
| expect(material.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(2.0))); |
| expect(material.textStyle.color, const Color(0xdd000000)); |
| expect(material.textStyle.fontFamily, 'Roboto'); |
| expect(material.textStyle.fontSize, 14); |
| expect(material.textStyle.fontWeight, FontWeight.w500); |
| expect(material.type, MaterialType.button); |
| |
| // Disabled RaisedButton |
| await tester.pumpWidget( |
| const Directionality( |
| textDirection: TextDirection.ltr, |
| child: RaisedButton( |
| onPressed: null, |
| child: Text('button'), |
| ), |
| ), |
| ); |
| material = tester.widget<Material>(rawButtonMaterial); |
| expect(material.animationDuration, const Duration(milliseconds: 200)); |
| expect(material.borderOnForeground, true); |
| expect(material.borderRadius, null); |
| expect(material.clipBehavior, Clip.none); |
| expect(material.color, const Color(0x61000000)); |
| expect(material.elevation, 0.0); |
| expect(material.shadowColor, const Color(0xff000000)); |
| expect(material.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(2.0))); |
| expect(material.textStyle.color, const Color(0x61000000)); |
| expect(material.textStyle.fontFamily, 'Roboto'); |
| expect(material.textStyle.fontSize, 14); |
| expect(material.textStyle.fontWeight, FontWeight.w500); |
| expect(material.type, MaterialType.button); |
| }); |
| |
| testWidgets('OutlineButton defaults', (WidgetTester tester) async { |
| final Finder rawButtonMaterial = find.descendant( |
| of: find.byType(OutlineButton), |
| matching: find.byType(Material), |
| ); |
| |
| // Enabled OutlineButton |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: OutlineButton( |
| onPressed: () { }, |
| child: const Text('button'), |
| ), |
| ), |
| ); |
| Material material = tester.widget<Material>(rawButtonMaterial); |
| expect(material.animationDuration, const Duration(milliseconds: 75)); |
| expect(material.borderOnForeground, true); |
| expect(material.borderRadius, null); |
| expect(material.clipBehavior, Clip.none); |
| expect(material.color, const Color(0x00000000)); |
| expect(material.elevation, 0.0); |
| expect(material.shadowColor, const Color(0xff000000)); |
| expect(material.textStyle.color, const Color(0xdd000000)); |
| expect(material.textStyle.fontFamily, 'Roboto'); |
| expect(material.textStyle.fontSize, 14); |
| expect(material.textStyle.fontWeight, FontWeight.w500); |
| expect(material.type, MaterialType.button); |
| |
| final Offset center = tester.getCenter(find.byType(OutlineButton)); |
| await tester.startGesture(center); |
| await tester.pumpAndSettle(); |
| |
| // No change vs enabled and not pressed. |
| material = tester.widget<Material>(rawButtonMaterial); |
| expect(material.animationDuration, const Duration(milliseconds: 75)); |
| expect(material.borderOnForeground, true); |
| expect(material.borderRadius, null); |
| expect(material.clipBehavior, Clip.none); |
| expect(material.color, const Color(0x00000000)); |
| expect(material.elevation, 0.0); |
| expect(material.shadowColor, const Color(0xff000000)); |
| expect(material.textStyle.color, const Color(0xdd000000)); |
| expect(material.textStyle.fontFamily, 'Roboto'); |
| expect(material.textStyle.fontSize, 14); |
| expect(material.textStyle.fontWeight, FontWeight.w500); |
| expect(material.type, MaterialType.button); |
| |
| // Disabled OutlineButton |
| await tester.pumpWidget( |
| const Directionality( |
| textDirection: TextDirection.ltr, |
| child: OutlineButton( |
| onPressed: null, |
| child: Text('button'), |
| ), |
| ), |
| ); |
| material = tester.widget<Material>(rawButtonMaterial); |
| expect(material.animationDuration, const Duration(milliseconds: 75)); |
| expect(material.borderOnForeground, true); |
| expect(material.borderRadius, null); |
| expect(material.clipBehavior, Clip.none); |
| expect(material.color, const Color(0x00000000)); |
| expect(material.elevation, 0.0); |
| expect(material.shadowColor, const Color(0xff000000)); |
| expect(material.textStyle.color, const Color(0x61000000)); |
| expect(material.textStyle.fontFamily, 'Roboto'); |
| expect(material.textStyle.fontSize, 14); |
| expect(material.textStyle.fontWeight, FontWeight.w500); |
| expect(material.type, MaterialType.button); |
| }); |
| |
| testWidgets('Do buttons work with hover', (WidgetTester tester) async { |
| const Color hoverColor = Color(0xff001122); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: FlatButton( |
| hoverColor: hoverColor, |
| onPressed: () { }, |
| child: const Text('button'), |
| ), |
| ), |
| ); |
| |
| final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); |
| await gesture.addPointer(); |
| await gesture.moveTo(tester.getCenter(find.byType(FlatButton))); |
| await tester.pumpAndSettle(); |
| |
| RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); |
| expect(inkFeatures, paints..rect(color: hoverColor)); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: OutlineButton( |
| hoverColor: hoverColor, |
| onPressed: () { }, |
| child: const Text('button'), |
| ), |
| ), |
| ); |
| |
| await tester.pumpAndSettle(); |
| inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); |
| expect(inkFeatures, paints..rect(color: hoverColor)); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: RaisedButton( |
| hoverColor: hoverColor, |
| onPressed: () { }, |
| child: const Text('button'), |
| ), |
| ), |
| ); |
| |
| await tester.pumpAndSettle(); |
| inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); |
| expect(inkFeatures, paints..rect(color: hoverColor)); |
| |
| gesture.removePointer(); |
| }); |
| |
| testWidgets('Do buttons work with focus', (WidgetTester tester) async { |
| const Color focusColor = Color(0xff001122); |
| |
| FocusNode focusNode = FocusNode(debugLabel: 'FlatButton Node'); |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: FlatButton( |
| focusColor: focusColor, |
| focusNode: focusNode, |
| onPressed: () { }, |
| child: const Text('button'), |
| ), |
| ), |
| ); |
| |
| FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; |
| focusNode.requestFocus(); |
| await tester.pumpAndSettle(); |
| |
| RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); |
| expect(inkFeatures, paints..rect(color: focusColor)); |
| |
| focusNode = FocusNode(debugLabel: 'RaisedButton Node'); |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: RaisedButton( |
| focusColor: focusColor, |
| focusNode: focusNode, |
| onPressed: () { }, |
| child: const Text('button'), |
| ), |
| ), |
| ); |
| focusNode.requestFocus(); |
| await tester.pumpAndSettle(); |
| inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); |
| expect(inkFeatures, paints..rect(color: focusColor)); |
| |
| focusNode = FocusNode(debugLabel: 'OutlineButton Node'); |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: OutlineButton( |
| focusColor: focusColor, |
| focusNode: focusNode, |
| onPressed: () { }, |
| child: const Text('button'), |
| ), |
| ), |
| ); |
| focusNode.requestFocus(); |
| await tester.pumpAndSettle(); |
| inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); |
| expect(inkFeatures, paints..rect(color: focusColor)); |
| }); |
| |
| testWidgets('Does FlatButton contribute semantics', (WidgetTester tester) async { |
| final SemanticsTester semantics = SemanticsTester(tester); |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Material( |
| child: Center( |
| child: FlatButton( |
| onPressed: () { }, |
| child: const Text('ABC'), |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(semantics, hasSemantics( |
| TestSemantics.root( |
| children: <TestSemantics>[ |
| TestSemantics.rootChild( |
| actions: <SemanticsAction>[ |
| SemanticsAction.tap, |
| ], |
| label: 'ABC', |
| rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0), |
| transform: Matrix4.translationValues(356.0, 276.0, 0.0), |
| flags: <SemanticsFlag>[ |
| SemanticsFlag.hasEnabledState, |
| SemanticsFlag.isButton, |
| SemanticsFlag.isEnabled, |
| SemanticsFlag.isFocusable, |
| ], |
| ), |
| ], |
| ), |
| ignoreId: true, |
| )); |
| |
| semantics.dispose(); |
| }); |
| |
| testWidgets('Does RaisedButton contribute semantics', (WidgetTester tester) async { |
| final SemanticsTester semantics = SemanticsTester(tester); |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Material( |
| child: Center( |
| child: RaisedButton( |
| onPressed: () { }, |
| child: const Text('ABC'), |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(semantics, hasSemantics( |
| TestSemantics.root( |
| children: <TestSemantics>[ |
| TestSemantics.rootChild( |
| actions: <SemanticsAction>[ |
| SemanticsAction.tap, |
| ], |
| label: 'ABC', |
| rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0), |
| transform: Matrix4.translationValues(356.0, 276.0, 0.0), |
| flags: <SemanticsFlag>[ |
| SemanticsFlag.hasEnabledState, |
| SemanticsFlag.isButton, |
| SemanticsFlag.isEnabled, |
| SemanticsFlag.isFocusable, |
| ], |
| ), |
| ], |
| ), |
| ignoreId: true, |
| )); |
| |
| semantics.dispose(); |
| }); |
| |
| testWidgets('Does FlatButton scale with font scale changes', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Material( |
| child: MediaQuery( |
| data: const MediaQueryData(textScaleFactor: 1.0), |
| child: Center( |
| child: FlatButton( |
| onPressed: () { }, |
| child: const Text('ABC'), |
| ), |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(tester.getSize(find.byType(FlatButton)), equals(const Size(88.0, 48.0))); |
| expect(tester.getSize(find.byType(Text)), equals(const Size(42.0, 14.0))); |
| |
| // textScaleFactor expands text, but not button. |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Material( |
| child: MediaQuery( |
| data: const MediaQueryData(textScaleFactor: 1.3), |
| child: Center( |
| child: FlatButton( |
| onPressed: () { }, |
| child: const Text('ABC'), |
| ), |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(tester.getSize(find.byType(FlatButton)), equals(const Size(88.0, 48.0))); |
| // Scaled text rendering is different on Linux and Mac by one pixel. |
| // TODO(gspencergoog): Figure out why this is, and fix it. https://github.com/flutter/flutter/issues/12357 |
| expect(tester.getSize(find.byType(Text)).width, isIn(<double>[54.0, 55.0])); |
| expect(tester.getSize(find.byType(Text)).height, isIn(<double>[18.0, 19.0])); |
| |
| // Set text scale large enough to expand text and button. |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Material( |
| child: MediaQuery( |
| data: const MediaQueryData(textScaleFactor: 3.0), |
| child: Center( |
| child: FlatButton( |
| onPressed: () { }, |
| child: const Text('ABC'), |
| ), |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| // Scaled text rendering is different on Linux and Mac by one pixel. |
| // TODO(gspencergoog): Figure out why this is, and fix it. https://github.com/flutter/flutter/issues/12357 |
| expect(tester.getSize(find.byType(FlatButton)).width, isIn(<double>[158.0, 159.0])); |
| expect(tester.getSize(find.byType(FlatButton)).height, equals(48.0)); |
| expect(tester.getSize(find.byType(Text)).width, isIn(<double>[126.0, 127.0])); |
| expect(tester.getSize(find.byType(Text)).height, equals(42.0)); |
| }, skip: isBrowser); |
| |
| testWidgets('FlatButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { |
| final Key key1 = UniqueKey(); |
| await tester.pumpWidget( |
| Theme( |
| data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.padded), |
| child: Directionality( |
| textDirection: TextDirection.ltr, |
| child: Material( |
| child: Center( |
| child: FlatButton( |
| key: key1, |
| child: const SizedBox(width: 50.0, height: 8.0), |
| onPressed: () { }, |
| ), |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(tester.getSize(find.byKey(key1)), const Size(88.0, 48.0)); |
| |
| final Key key2 = UniqueKey(); |
| await tester.pumpWidget( |
| Theme( |
| data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap), |
| child: Directionality( |
| textDirection: TextDirection.ltr, |
| child: Material( |
| child: Center( |
| child: FlatButton( |
| key: key2, |
| child: const SizedBox(width: 50.0, height: 8.0), |
| onPressed: () { }, |
| ), |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(tester.getSize(find.byKey(key2)), const Size(88.0, 36.0)); |
| }); |
| |
| testWidgets('RaisedButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { |
| final Key key1 = UniqueKey(); |
| await tester.pumpWidget( |
| Theme( |
| data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.padded), |
| child: Directionality( |
| textDirection: TextDirection.ltr, |
| child: Material( |
| child: Center( |
| child: RaisedButton( |
| key: key1, |
| child: const SizedBox(width: 50.0, height: 8.0), |
| onPressed: () { }, |
| ), |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(tester.getSize(find.byKey(key1)), const Size(88.0, 48.0)); |
| |
| final Key key2 = UniqueKey(); |
| await tester.pumpWidget( |
| Theme( |
| data: ThemeData(materialTapTargetSize: MaterialTapTargetSize.shrinkWrap), |
| child: Directionality( |
| textDirection: TextDirection.ltr, |
| child: Material( |
| child: Center( |
| child: RaisedButton( |
| key: key2, |
| child: const SizedBox(width: 50.0, height: 8.0), |
| onPressed: () { }, |
| ), |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| expect(tester.getSize(find.byKey(key2)), const Size(88.0, 36.0)); |
| }); |
| |
| testWidgets('RaisedButton has no clip by default', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: Material( |
| child: RaisedButton( |
| onPressed: () { /* to make sure the button is enabled */ }, |
| ), |
| ), |
| ), |
| ); |
| |
| expect( |
| tester.renderObject(find.byType(RaisedButton)), |
| paintsExactlyCountTimes(#clipPath, 0), |
| ); |
| }); |
| } |