1994 lines
66 KiB
Dart
1994 lines
66 KiB
Dart
// 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.
|
|
|
|
// This file is run as part of a reduced test set in CI on Mac and Windows
|
|
// machines.
|
|
@Tags(<String>['reduced-test-set'])
|
|
library;
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/gestures.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import '../widgets/semantics_tester.dart';
|
|
|
|
const double _defaultBorderWidth = 1.0;
|
|
|
|
Widget boilerplate({
|
|
ThemeData? theme,
|
|
MaterialTapTargetSize? tapTargetSize,
|
|
required Widget child,
|
|
}) {
|
|
return Theme(
|
|
data: theme ?? ThemeData(materialTapTargetSize: tapTargetSize),
|
|
child: Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(child: Material(child: child)),
|
|
),
|
|
);
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('Initial toggle state is reflected', (WidgetTester tester) async {
|
|
TextStyle buttonTextStyle(String text) {
|
|
return tester
|
|
.widget<DefaultTextStyle>(
|
|
find.descendant(
|
|
of: find.widgetWithText(TextButton, text),
|
|
matching: find.byType(DefaultTextStyle),
|
|
),
|
|
)
|
|
.style;
|
|
}
|
|
|
|
final theme = ThemeData();
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
onPressed: (int index) {},
|
|
isSelected: const <bool>[false, true],
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(buttonTextStyle('First child').color, theme.colorScheme.onSurface.withOpacity(0.87));
|
|
expect(buttonTextStyle('Second child').color, theme.colorScheme.primary);
|
|
});
|
|
|
|
testWidgets('onPressed is triggered on button tap', (WidgetTester tester) async {
|
|
TextStyle buttonTextStyle(String text) {
|
|
return tester
|
|
.widget<DefaultTextStyle>(
|
|
find.descendant(
|
|
of: find.widgetWithText(TextButton, text),
|
|
matching: find.byType(DefaultTextStyle),
|
|
),
|
|
)
|
|
.style;
|
|
}
|
|
|
|
final isSelected = <bool>[false, true];
|
|
final theme = ThemeData();
|
|
await tester.pumpWidget(
|
|
StatefulBuilder(
|
|
builder: (BuildContext context, StateSetter setState) {
|
|
return boilerplate(
|
|
child: ToggleButtons(
|
|
onPressed: (int index) {
|
|
setState(() {
|
|
isSelected[index] = !isSelected[index];
|
|
});
|
|
},
|
|
isSelected: isSelected,
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
|
|
expect(isSelected[0], isFalse);
|
|
expect(isSelected[1], isTrue);
|
|
expect(buttonTextStyle('First child').color, theme.colorScheme.onSurface.withOpacity(0.87));
|
|
expect(buttonTextStyle('Second child').color, theme.colorScheme.primary);
|
|
|
|
await tester.tap(find.text('Second child'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(isSelected[0], isFalse);
|
|
expect(isSelected[1], isFalse);
|
|
expect(buttonTextStyle('First child').color, theme.colorScheme.onSurface.withOpacity(0.87));
|
|
expect(buttonTextStyle('Second child').color, theme.colorScheme.onSurface.withOpacity(0.87));
|
|
});
|
|
|
|
testWidgets('onPressed that is null disables buttons', (WidgetTester tester) async {
|
|
TextStyle buttonTextStyle(String text) {
|
|
return tester
|
|
.widget<DefaultTextStyle>(
|
|
find.descendant(
|
|
of: find.widgetWithText(TextButton, text),
|
|
matching: find.byType(DefaultTextStyle),
|
|
),
|
|
)
|
|
.style;
|
|
}
|
|
|
|
final isSelected = <bool>[false, true];
|
|
final theme = ThemeData();
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: isSelected,
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(isSelected[0], isFalse);
|
|
expect(isSelected[1], isTrue);
|
|
expect(buttonTextStyle('First child').color, theme.colorScheme.onSurface.withOpacity(0.38));
|
|
expect(buttonTextStyle('Second child').color, theme.colorScheme.onSurface.withOpacity(0.38));
|
|
|
|
await tester.tap(find.text('Second child'));
|
|
await tester.pumpAndSettle();
|
|
|
|
// Nothing should change
|
|
expect(isSelected[0], isFalse);
|
|
expect(isSelected[1], isTrue);
|
|
expect(buttonTextStyle('First child').color, theme.colorScheme.onSurface.withOpacity(0.38));
|
|
expect(buttonTextStyle('Second child').color, theme.colorScheme.onSurface.withOpacity(0.38));
|
|
});
|
|
|
|
testWidgets('children and isSelected properties have to be the same length', (
|
|
WidgetTester tester,
|
|
) async {
|
|
await expectLater(
|
|
() => tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[false],
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
),
|
|
),
|
|
throwsA(
|
|
isAssertionError.having(
|
|
(AssertionError error) => error.toString(),
|
|
'.toString()',
|
|
allOf(contains('children.length'), contains('isSelected.length')),
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
testWidgets('Default text style is applied', (WidgetTester tester) async {
|
|
final theme = ThemeData();
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
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.fontFamily, theme.textTheme.bodyMedium!.fontFamily);
|
|
expect(textStyle.decoration, theme.textTheme.bodyMedium!.decoration);
|
|
|
|
textStyle = tester
|
|
.widget<DefaultTextStyle>(
|
|
find.descendant(
|
|
of: find.widgetWithText(TextButton, 'Second child'),
|
|
matching: find.byType(DefaultTextStyle),
|
|
),
|
|
)
|
|
.style;
|
|
expect(textStyle.fontFamily, theme.textTheme.bodyMedium!.fontFamily);
|
|
expect(textStyle.decoration, theme.textTheme.bodyMedium!.decoration);
|
|
});
|
|
|
|
testWidgets('Custom text style except color is applied', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[false, true],
|
|
onPressed: (int index) {},
|
|
textStyle: const TextStyle(
|
|
textBaseline: TextBaseline.ideographic,
|
|
fontSize: 20.0,
|
|
color: Colors.orange,
|
|
),
|
|
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));
|
|
});
|
|
|
|
testWidgets('Default BoxConstraints', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[false, false, false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Icon(Icons.check), Icon(Icons.access_alarm), Icon(Icons.cake)],
|
|
),
|
|
),
|
|
);
|
|
|
|
final Rect firstRect = tester.getRect(find.byType(TextButton).at(0));
|
|
expect(firstRect.width, 48.0);
|
|
expect(firstRect.height, 48.0);
|
|
final Rect secondRect = tester.getRect(find.byType(TextButton).at(1));
|
|
expect(secondRect.width, 48.0);
|
|
expect(secondRect.height, 48.0);
|
|
final Rect thirdRect = tester.getRect(find.byType(TextButton).at(2));
|
|
expect(thirdRect.width, 48.0);
|
|
expect(thirdRect.height, 48.0);
|
|
});
|
|
|
|
testWidgets('Custom BoxConstraints', (WidgetTester tester) async {
|
|
// Test for minimum constraints
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
constraints: const BoxConstraints(minWidth: 50.0, minHeight: 60.0),
|
|
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(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
|
constraints: const BoxConstraints(maxWidth: 20.0, maxHeight: 10.0),
|
|
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);
|
|
});
|
|
|
|
testWidgets('Default 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))
|
|
.last,
|
|
);
|
|
}
|
|
|
|
final theme = ThemeData();
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[
|
|
Row(children: <Widget>[Text('First child'), Icon(Icons.check)]),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
// Default enabled color
|
|
expect(buttonTextStyle('First child').color, theme.colorScheme.onSurface.withOpacity(0.87));
|
|
expect(iconTheme(Icons.check).data.color, theme.colorScheme.onSurface.withOpacity(0.87));
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[true],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[
|
|
Row(children: <Widget>[Text('First child'), Icon(Icons.check)]),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
// Default selected color
|
|
expect(buttonTextStyle('First child').color, theme.colorScheme.primary);
|
|
expect(iconTheme(Icons.check).data.color, theme.colorScheme.primary);
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[true],
|
|
children: const <Widget>[
|
|
Row(children: <Widget>[Text('First child'), Icon(Icons.check)]),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
// Default disabled color
|
|
expect(buttonTextStyle('First child').color, theme.colorScheme.onSurface.withOpacity(0.38));
|
|
expect(iconTheme(Icons.check).data.color, theme.colorScheme.onSurface.withOpacity(0.38));
|
|
});
|
|
|
|
testWidgets('Custom 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))
|
|
.last,
|
|
);
|
|
}
|
|
|
|
final theme = ThemeData();
|
|
const Color enabledColor = Colors.lime;
|
|
const Color selectedColor = Colors.green;
|
|
const Color disabledColor = Colors.yellow;
|
|
|
|
// Tests are ineffective if the custom colors are the same as the theme's
|
|
expect(theme.colorScheme.onSurface, isNot(enabledColor));
|
|
expect(theme.colorScheme.primary, isNot(selectedColor));
|
|
expect(theme.colorScheme.onSurface.withOpacity(0.38), isNot(disabledColor));
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
color: enabledColor,
|
|
isSelected: const <bool>[false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[
|
|
Row(children: <Widget>[Text('First child'), Icon(Icons.check)]),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
// Custom enabled color
|
|
expect(buttonTextStyle('First child').color, enabledColor);
|
|
expect(iconTheme(Icons.check).data.color, enabledColor);
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
selectedColor: selectedColor,
|
|
isSelected: const <bool>[true],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[
|
|
Row(children: <Widget>[Text('First child'), Icon(Icons.check)]),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
// Custom selected color
|
|
expect(buttonTextStyle('First child').color, selectedColor);
|
|
expect(iconTheme(Icons.check).data.color, selectedColor);
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
disabledColor: disabledColor,
|
|
isSelected: const <bool>[true],
|
|
children: const <Widget>[
|
|
Row(children: <Widget>[Text('First child'), Icon(Icons.check)]),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
// Custom disabled color
|
|
expect(buttonTextStyle('First child').color, disabledColor);
|
|
expect(iconTheme(Icons.check).data.color, disabledColor);
|
|
});
|
|
|
|
testWidgets('Default button fillColor - unselected', (WidgetTester tester) async {
|
|
final theme = ThemeData();
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[false],
|
|
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, theme.colorScheme.surface.withOpacity(0.0));
|
|
expect(material.type, MaterialType.button);
|
|
});
|
|
|
|
testWidgets('Default button fillColor - selected', (WidgetTester tester) async {
|
|
final theme = ThemeData();
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
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, theme.colorScheme.primary.withOpacity(0.12));
|
|
expect(material.type, MaterialType.button);
|
|
});
|
|
|
|
testWidgets('Default button fillColor - disabled', (WidgetTester tester) async {
|
|
final theme = ThemeData();
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[true],
|
|
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, theme.colorScheme.surface.withOpacity(0.0));
|
|
expect(material.type, MaterialType.button);
|
|
});
|
|
|
|
testWidgets('Custom button fillColor', (WidgetTester tester) async {
|
|
const Color customFillColor = Colors.green;
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
fillColor: customFillColor,
|
|
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);
|
|
});
|
|
|
|
testWidgets('Custom button fillColor - Non WidgetState', (WidgetTester tester) async {
|
|
Material buttonColor(String text) {
|
|
return tester.widget<Material>(
|
|
find.descendant(of: find.byType(TextButton), matching: find.widgetWithText(Material, text)),
|
|
);
|
|
}
|
|
|
|
final theme = ThemeData();
|
|
const Color selectedFillColor = Colors.yellow;
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
fillColor: selectedFillColor,
|
|
isSelected: const <bool>[false, true],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(buttonColor('First child').color, theme.colorScheme.surface.withOpacity(0.0));
|
|
expect(buttonColor('Second child').color, selectedFillColor);
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
fillColor: selectedFillColor,
|
|
isSelected: const <bool>[false, true],
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(buttonColor('First child').color, theme.colorScheme.surface.withOpacity(0.0));
|
|
expect(buttonColor('Second child').color, theme.colorScheme.surface.withOpacity(0.0));
|
|
});
|
|
|
|
testWidgets('Custom button fillColor - WidgetState', (WidgetTester tester) async {
|
|
Material buttonColor(String text) {
|
|
return tester.widget<Material>(
|
|
find.descendant(of: find.byType(TextButton), matching: find.widgetWithText(Material, text)),
|
|
);
|
|
}
|
|
|
|
const Color selectedFillColor = Colors.orange;
|
|
const Color defaultFillColor = Colors.blue;
|
|
|
|
Color getFillColor(Set<WidgetState> states) {
|
|
if (states.contains(WidgetState.selected)) {
|
|
return selectedFillColor;
|
|
}
|
|
return defaultFillColor;
|
|
}
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
fillColor: WidgetStateColor.resolveWith(getFillColor),
|
|
isSelected: const <bool>[false, true],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(buttonColor('First child').color, defaultFillColor);
|
|
expect(buttonColor('Second child').color, selectedFillColor);
|
|
|
|
// disabled
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
fillColor: WidgetStateColor.resolveWith(getFillColor),
|
|
isSelected: const <bool>[false, true],
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(buttonColor('First child').color, defaultFillColor);
|
|
expect(buttonColor('Second child').color, defaultFillColor);
|
|
});
|
|
|
|
testWidgets('Default InkWell colors - unselected', (WidgetTester tester) async {
|
|
final theme = ThemeData();
|
|
final focusNode = FocusNode();
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[false],
|
|
onPressed: (int index) {},
|
|
focusNodes: <FocusNode>[focusNode],
|
|
children: const <Widget>[Text('First child')],
|
|
),
|
|
),
|
|
);
|
|
|
|
final Offset center = tester.getCenter(find.text('First child'));
|
|
|
|
// hoverColor
|
|
final TestGesture hoverGesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
|
await hoverGesture.addPointer();
|
|
await hoverGesture.moveTo(center);
|
|
await tester.pumpAndSettle();
|
|
await hoverGesture.moveTo(Offset.zero);
|
|
|
|
RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) {
|
|
return object.runtimeType.toString() == '_RenderInkFeatures';
|
|
});
|
|
expect(inkFeatures, paints..rect(color: theme.colorScheme.onSurface.withOpacity(0.04)));
|
|
|
|
// splashColor
|
|
final TestGesture touchGesture = await tester.createGesture();
|
|
await touchGesture.down(center); // The button is on hovered and pressed
|
|
await tester.pumpAndSettle();
|
|
|
|
inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) {
|
|
return object.runtimeType.toString() == '_RenderInkFeatures';
|
|
});
|
|
expect(inkFeatures, paints..circle(color: theme.colorScheme.onSurface.withOpacity(0.16)));
|
|
|
|
await touchGesture.up();
|
|
await tester.pumpAndSettle();
|
|
await hoverGesture.moveTo(const Offset(0, 50));
|
|
await tester.pumpAndSettle();
|
|
|
|
// focusColor
|
|
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
|
focusNode.requestFocus();
|
|
await tester.pumpAndSettle();
|
|
inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) {
|
|
return object.runtimeType.toString() == '_RenderInkFeatures';
|
|
});
|
|
expect(inkFeatures, paints..rect(color: theme.colorScheme.onSurface.withOpacity(0.12)));
|
|
|
|
await hoverGesture.removePointer();
|
|
|
|
focusNode.dispose();
|
|
});
|
|
|
|
testWidgets('Default InkWell colors - selected', (WidgetTester tester) async {
|
|
final theme = ThemeData();
|
|
final focusNode = FocusNode();
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
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'));
|
|
|
|
// hoverColor
|
|
final TestGesture hoverGesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
|
await hoverGesture.addPointer();
|
|
await hoverGesture.moveTo(center);
|
|
await tester.pumpAndSettle();
|
|
|
|
RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) {
|
|
return object.runtimeType.toString() == '_RenderInkFeatures';
|
|
});
|
|
expect(inkFeatures, paints..rect(color: theme.colorScheme.primary.withOpacity(0.04)));
|
|
await hoverGesture.moveTo(Offset.zero);
|
|
|
|
// splashColor
|
|
final TestGesture touchGesture = await tester.createGesture();
|
|
await touchGesture.down(center); // The button is on hovered and pressed
|
|
await tester.pumpAndSettle();
|
|
|
|
inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) {
|
|
return object.runtimeType.toString() == '_RenderInkFeatures';
|
|
});
|
|
expect(inkFeatures, paints..circle(color: theme.colorScheme.primary.withOpacity(0.16)));
|
|
|
|
await touchGesture.up();
|
|
await tester.pumpAndSettle();
|
|
await hoverGesture.moveTo(const Offset(0, 50));
|
|
await tester.pumpAndSettle();
|
|
|
|
// focusColor
|
|
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
|
focusNode.requestFocus();
|
|
await tester.pumpAndSettle();
|
|
inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) {
|
|
return object.runtimeType.toString() == '_RenderInkFeatures';
|
|
});
|
|
expect(inkFeatures, paints..rect(color: theme.colorScheme.primary.withOpacity(0.12)));
|
|
|
|
await hoverGesture.removePointer();
|
|
|
|
focusNode.dispose();
|
|
});
|
|
|
|
testWidgets('Custom InkWell colors', (WidgetTester tester) async {
|
|
const splashColor = Color(0xff4caf50);
|
|
const highlightColor = Color(0xffcddc39);
|
|
const hoverColor = Color(0xffffeb3b);
|
|
const focusColor = Color(0xffffff00);
|
|
final focusNode = FocusNode();
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
splashColor: splashColor,
|
|
highlightColor: highlightColor,
|
|
hoverColor: hoverColor,
|
|
focusColor: focusColor,
|
|
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
|
|
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
|
|
FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
|
|
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();
|
|
|
|
focusNode.dispose();
|
|
});
|
|
|
|
testWidgets('Default border width and border colors for enabled, selected and disabled states', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final theme = ThemeData();
|
|
const defaultBorderWidth = 1.0;
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
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
|
|
..path()
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: defaultBorderWidth,
|
|
),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
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
|
|
..path()
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: defaultBorderWidth,
|
|
),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
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
|
|
..path()
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: defaultBorderWidth,
|
|
),
|
|
);
|
|
});
|
|
|
|
testWidgets('Custom border width and border colors for enabled, selected and disabled states', (
|
|
WidgetTester tester,
|
|
) async {
|
|
const borderColor = Color(0xff4caf50);
|
|
const selectedBorderColor = Color(0xffcddc39);
|
|
const disabledBorderColor = Color(0xffffeb3b);
|
|
const customWidth = 2.0;
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
borderColor: borderColor,
|
|
borderWidth: customWidth,
|
|
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
|
|
..path()
|
|
..path(style: PaintingStyle.stroke, color: borderColor, strokeWidth: customWidth),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
selectedBorderColor: selectedBorderColor,
|
|
borderWidth: customWidth,
|
|
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
|
|
..path()
|
|
..path(style: PaintingStyle.stroke, color: selectedBorderColor, strokeWidth: customWidth),
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
disabledBorderColor: disabledBorderColor,
|
|
borderWidth: customWidth,
|
|
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
|
|
..path()
|
|
..path(style: PaintingStyle.stroke, color: disabledBorderColor, strokeWidth: customWidth),
|
|
);
|
|
});
|
|
|
|
testWidgets('Height of segmented control is determined by tallest widget', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final children = <Widget>[
|
|
Container(constraints: const BoxConstraints.tightFor(height: 100.0)),
|
|
Container(
|
|
constraints: const BoxConstraints.tightFor(height: 400.0), // tallest widget
|
|
),
|
|
Container(constraints: const BoxConstraints.tightFor(height: 200.0)),
|
|
];
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(isSelected: const <bool>[false, true, false], children: children),
|
|
),
|
|
);
|
|
|
|
final List<Widget> toggleButtons = tester.allWidgets.where((Widget widget) {
|
|
return widget.runtimeType.toString() == '_SelectToggleButton';
|
|
}).toList();
|
|
|
|
for (var i = 0; i < toggleButtons.length; i++) {
|
|
final Rect rect = tester.getRect(find.byWidget(toggleButtons[i]));
|
|
expect(rect.height, 400.0 + 2 * _defaultBorderWidth);
|
|
}
|
|
});
|
|
|
|
testWidgets('Sizes of toggle buttons rebuilds with the correct dimensions', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final children = <Widget>[
|
|
Container(constraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0)),
|
|
Container(constraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0)),
|
|
Container(constraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0)),
|
|
];
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(isSelected: const <bool>[false, true, false], children: children),
|
|
),
|
|
);
|
|
|
|
List<Widget> toggleButtons;
|
|
toggleButtons = tester.allWidgets.where((Widget widget) {
|
|
return widget.runtimeType.toString() == '_SelectToggleButton';
|
|
}).toList();
|
|
|
|
for (var i = 0; i < toggleButtons.length; i++) {
|
|
final Rect rect = tester.getRect(find.byWidget(toggleButtons[i]));
|
|
expect(rect.height, 100.0 + 2 * _defaultBorderWidth);
|
|
|
|
// Only the last button paints both leading and trailing borders.
|
|
// Other buttons only paint the leading border.
|
|
if (i == toggleButtons.length - 1) {
|
|
expect(rect.width, 100.0 + 2 * _defaultBorderWidth);
|
|
} else {
|
|
expect(rect.width, 100.0 + 1 * _defaultBorderWidth);
|
|
}
|
|
}
|
|
|
|
final childrenRebuilt = <Widget>[
|
|
Container(constraints: const BoxConstraints.tightFor(width: 200.0, height: 200.0)),
|
|
Container(constraints: const BoxConstraints.tightFor(width: 200.0, height: 200.0)),
|
|
Container(constraints: const BoxConstraints.tightFor(width: 200.0, height: 200.0)),
|
|
];
|
|
|
|
// Update border width and widget sized to verify layout updates correctly
|
|
const customBorderWidth = 5.0;
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
borderWidth: customBorderWidth,
|
|
isSelected: const <bool>[false, true, false],
|
|
children: childrenRebuilt,
|
|
),
|
|
),
|
|
);
|
|
|
|
toggleButtons = tester.allWidgets.where((Widget widget) {
|
|
return widget.runtimeType.toString() == '_SelectToggleButton';
|
|
}).toList();
|
|
|
|
// Only the last button paints both leading and trailing borders.
|
|
// Other buttons only paint the leading border.
|
|
for (var i = 0; i < toggleButtons.length; i++) {
|
|
final Rect rect = tester.getRect(find.byWidget(toggleButtons[i]));
|
|
expect(rect.height, 200.0 + 2 * customBorderWidth);
|
|
if (i == toggleButtons.length - 1) {
|
|
expect(rect.width, 200.0 + 2 * customBorderWidth);
|
|
} else {
|
|
expect(rect.width, 200.0 + 1 * customBorderWidth);
|
|
}
|
|
}
|
|
});
|
|
|
|
testWidgets('Material2 - ToggleButtons text baseline alignment', (WidgetTester tester) async {
|
|
// The font size must be a multiple of 4 until
|
|
// https://github.com/flutter/flutter/issues/122066 is resolved.
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
theme: ThemeData(useMaterial3: false),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.baseline,
|
|
textBaseline: TextBaseline.alphabetic,
|
|
children: <Widget>[
|
|
ToggleButtons(
|
|
borderWidth: 5.0,
|
|
isSelected: const <bool>[false, true],
|
|
children: const <Widget>[
|
|
Text('First child', style: TextStyle(fontFamily: 'FlutterTest', fontSize: 8.0)),
|
|
Text('Second child', style: TextStyle(fontFamily: 'FlutterTest', fontSize: 8.0)),
|
|
],
|
|
),
|
|
ElevatedButton(
|
|
onPressed: null,
|
|
style: ElevatedButton.styleFrom(
|
|
textStyle: const TextStyle(fontFamily: 'FlutterTest', fontSize: 20.0),
|
|
),
|
|
child: const Text('Elevated Button'),
|
|
),
|
|
const Text('Text', style: TextStyle(fontFamily: 'FlutterTest', fontSize: 28.0)),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
// The test font extends 0.25 * fontSize below the baseline.
|
|
// So the three row elements line up like this:
|
|
//
|
|
// ToggleButton MaterialButton Text
|
|
// ------------------------------------ baseline
|
|
// 2.0 5.0 7.0 space below the baseline = 0.25 * fontSize
|
|
// ------------------------------------ widget text dy values
|
|
|
|
final double firstToggleButtonDy = tester.getBottomLeft(find.text('First child')).dy;
|
|
final double secondToggleButtonDy = tester.getBottomLeft(find.text('Second child')).dy;
|
|
final double elevatedButtonDy = tester.getBottomLeft(find.text('Elevated Button')).dy;
|
|
final double textDy = tester.getBottomLeft(find.text('Text')).dy;
|
|
|
|
expect(firstToggleButtonDy, secondToggleButtonDy);
|
|
expect(firstToggleButtonDy, elevatedButtonDy - 3.0);
|
|
expect(firstToggleButtonDy, textDy - 5.0);
|
|
});
|
|
|
|
testWidgets('Material3 - ToggleButtons text baseline alignment', (WidgetTester tester) async {
|
|
// The point size of the fonts must be a multiple of 4 until
|
|
// https://github.com/flutter/flutter/issues/122066 is resolved.
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.baseline,
|
|
textBaseline: TextBaseline.alphabetic,
|
|
children: <Widget>[
|
|
ToggleButtons(
|
|
borderWidth: 5.0,
|
|
isSelected: const <bool>[false, true],
|
|
children: const <Widget>[
|
|
Text('First child', style: TextStyle(fontFamily: 'FlutterTest', fontSize: 8.0)),
|
|
Text('Second child', style: TextStyle(fontFamily: 'FlutterTest', fontSize: 8.0)),
|
|
],
|
|
),
|
|
ElevatedButton(
|
|
onPressed: null,
|
|
style: ElevatedButton.styleFrom(
|
|
textStyle: const TextStyle(fontFamily: 'FlutterTest', fontSize: 20.0),
|
|
),
|
|
child: const Text('Elevated Button'),
|
|
),
|
|
const Text('Text', style: TextStyle(fontFamily: 'FlutterTest', fontSize: 28.0)),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
// The test font extends 0.25 * fontSize below the baseline.
|
|
// So the three row elements line up like this:
|
|
//
|
|
// ToggleButton MaterialButton Text
|
|
// ------------------------------------ baseline
|
|
// 2.0 5.0 7.0 space below the baseline = 0.25 * fontSize
|
|
// ------------------------------------ widget text dy values
|
|
|
|
final double firstToggleButtonDy = tester.getBottomLeft(find.text('First child')).dy;
|
|
final double secondToggleButtonDy = tester.getBottomLeft(find.text('Second child')).dy;
|
|
final double elevatedButtonDy = tester.getBottomLeft(find.text('Elevated Button')).dy;
|
|
final double textDy = tester.getBottomLeft(find.text('Text')).dy;
|
|
|
|
expect(firstToggleButtonDy, secondToggleButtonDy);
|
|
expect(firstToggleButtonDy, closeTo(elevatedButtonDy - 1.7, 0.1));
|
|
expect(firstToggleButtonDy, closeTo(textDy - 9.7, 0.1));
|
|
});
|
|
|
|
testWidgets('Directionality test', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
Material(
|
|
child: Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Center(
|
|
child: ToggleButtons(
|
|
onPressed: (int index) {},
|
|
isSelected: const <bool>[false, true],
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
tester.getTopRight(find.text('First child')).dx <
|
|
tester.getTopRight(find.text('Second child')).dx,
|
|
isTrue,
|
|
);
|
|
|
|
await tester.pumpWidget(
|
|
Material(
|
|
child: Directionality(
|
|
textDirection: TextDirection.rtl,
|
|
child: Center(
|
|
child: ToggleButtons(
|
|
onPressed: (int index) {},
|
|
isSelected: const <bool>[false, true],
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
tester.getTopRight(find.text('First child')).dx >
|
|
tester.getTopRight(find.text('Second child')).dx,
|
|
isTrue,
|
|
);
|
|
});
|
|
|
|
testWidgets('Properly draws borders based on state', (WidgetTester tester) async {
|
|
final theme = ThemeData();
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[false, true, false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First child'), Text('Second child'), Text('Third child')],
|
|
),
|
|
),
|
|
);
|
|
|
|
final List<RenderObject> toggleButtonRenderObject = tester.allRenderObjects
|
|
.where((RenderObject object) {
|
|
return object.runtimeType.toString() == '_SelectToggleButtonRenderObject';
|
|
})
|
|
.toSet()
|
|
.toList();
|
|
|
|
// The first button paints the leading, top and bottom sides with a path
|
|
expect(
|
|
toggleButtonRenderObject[0],
|
|
paints
|
|
// physical model
|
|
..path()
|
|
// leading side, top and bottom - enabled
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: _defaultBorderWidth,
|
|
),
|
|
);
|
|
|
|
// The middle buttons paint a leading side path first, followed by a
|
|
// top and bottom side path
|
|
expect(
|
|
toggleButtonRenderObject[1],
|
|
paints
|
|
// physical model
|
|
..path()
|
|
// leading side - selected
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: _defaultBorderWidth,
|
|
)
|
|
// top and bottom - selected
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: _defaultBorderWidth,
|
|
),
|
|
);
|
|
|
|
// The last button paints a leading side path first, followed by
|
|
// a trailing, top and bottom side path
|
|
expect(
|
|
toggleButtonRenderObject[2],
|
|
paints
|
|
// physical model
|
|
..path()
|
|
// leading side - selected, since previous button is selected
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: _defaultBorderWidth,
|
|
)
|
|
// trailing side, top and bottom - enabled
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: _defaultBorderWidth,
|
|
),
|
|
);
|
|
});
|
|
|
|
testWidgets(
|
|
'Properly draws borders based on state when direction is vertical and verticalDirection is down.',
|
|
(WidgetTester tester) async {
|
|
final theme = ThemeData();
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
direction: Axis.vertical,
|
|
isSelected: const <bool>[false, true, false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[
|
|
Text('First child'),
|
|
Text('Second child'),
|
|
Text('Third child'),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
// The children should be laid out along vertical and the first child at top.
|
|
// The item height is icon height + default border width (48.0 + 1.0) pixels.
|
|
expect(tester.getCenter(find.text('First child')), const Offset(400.0, 251.0));
|
|
expect(tester.getCenter(find.text('Second child')), const Offset(400.0, 300.0));
|
|
expect(tester.getCenter(find.text('Third child')), const Offset(400.0, 349.0));
|
|
|
|
final List<RenderObject> toggleButtonRenderObject = tester.allRenderObjects
|
|
.where((RenderObject object) {
|
|
return object.runtimeType.toString() == '_SelectToggleButtonRenderObject';
|
|
})
|
|
.toSet()
|
|
.toList();
|
|
|
|
// The first button paints the left, top and right sides with a path.
|
|
expect(
|
|
toggleButtonRenderObject[0],
|
|
paints
|
|
// physical model
|
|
..path()
|
|
// left side, top and right - enabled.
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: _defaultBorderWidth,
|
|
),
|
|
);
|
|
|
|
// The middle buttons paint a top side path first, followed by a
|
|
// left and right side path.
|
|
expect(
|
|
toggleButtonRenderObject[1],
|
|
paints
|
|
// physical model
|
|
..path()
|
|
// top side - selected.
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: _defaultBorderWidth,
|
|
)
|
|
// left and right - selected.
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: _defaultBorderWidth,
|
|
),
|
|
);
|
|
|
|
// The last button paints a top side path first, followed by
|
|
// a left, bottom and right side path
|
|
expect(
|
|
toggleButtonRenderObject[2],
|
|
paints
|
|
// physical model
|
|
..path()
|
|
// top side - selected, since previous button is selected.
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: _defaultBorderWidth,
|
|
)
|
|
// left side, bottom and right - enabled.
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: _defaultBorderWidth,
|
|
),
|
|
);
|
|
},
|
|
);
|
|
|
|
testWidgets('VerticalDirection test when direction is vertical.', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
direction: Axis.vertical,
|
|
verticalDirection: VerticalDirection.up,
|
|
isSelected: const <bool>[false, true, false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First child'), Text('Second child'), Text('Third child')],
|
|
),
|
|
),
|
|
);
|
|
|
|
// The children should be laid out along vertical and the last child at top.
|
|
expect(tester.getCenter(find.text('Third child')), const Offset(400.0, 251.0));
|
|
expect(tester.getCenter(find.text('Second child')), const Offset(400.0, 300.0));
|
|
expect(tester.getCenter(find.text('First child')), const Offset(400.0, 349.0));
|
|
});
|
|
|
|
testWidgets('Material2 - Tap target size is configurable by ThemeData.materialTapTargetSize', (
|
|
WidgetTester tester,
|
|
) async {
|
|
Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) {
|
|
return boilerplate(
|
|
theme: ThemeData(useMaterial3: false),
|
|
tapTargetSize: tapTargetSize,
|
|
child: ToggleButtons(
|
|
key: key,
|
|
constraints: const BoxConstraints(minWidth: 32.0, minHeight: 32.0),
|
|
isSelected: const <bool>[false, true, false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First'), Text('Second'), Text('Third')],
|
|
),
|
|
);
|
|
}
|
|
|
|
final Key key1 = UniqueKey();
|
|
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1));
|
|
expect(tester.getSize(find.byKey(key1)), const Size(228.0, 48.0));
|
|
|
|
final Key key2 = UniqueKey();
|
|
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2));
|
|
expect(tester.getSize(find.byKey(key2)), const Size(228.0, 48.0));
|
|
});
|
|
|
|
testWidgets('Material3 - Tap target size is configurable by ThemeData.materialTapTargetSize', (
|
|
WidgetTester tester,
|
|
) async {
|
|
Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) {
|
|
return boilerplate(
|
|
tapTargetSize: tapTargetSize,
|
|
child: ToggleButtons(
|
|
key: key,
|
|
constraints: const BoxConstraints(minWidth: 32.0, minHeight: 32.0),
|
|
isSelected: const <bool>[false, true, false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First'), Text('Second'), Text('Third')],
|
|
),
|
|
);
|
|
}
|
|
|
|
final Key key1 = UniqueKey();
|
|
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1));
|
|
expect(tester.getSize(find.byKey(key1)), const Size(232.0, 48.0));
|
|
|
|
final Key key2 = UniqueKey();
|
|
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2));
|
|
expect(tester.getSize(find.byKey(key2)), const Size(232.0, 34.0));
|
|
});
|
|
|
|
testWidgets('Material2 - Tap target size is configurable', (WidgetTester tester) async {
|
|
Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) {
|
|
return boilerplate(
|
|
theme: ThemeData(useMaterial3: false),
|
|
child: ToggleButtons(
|
|
key: key,
|
|
tapTargetSize: tapTargetSize,
|
|
constraints: const BoxConstraints(minWidth: 32.0, minHeight: 32.0),
|
|
isSelected: const <bool>[false, true, false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First'), Text('Second'), Text('Third')],
|
|
),
|
|
);
|
|
}
|
|
|
|
final Key key1 = UniqueKey();
|
|
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1));
|
|
expect(tester.getSize(find.byKey(key1)), const Size(228.0, 48.0));
|
|
|
|
final Key key2 = UniqueKey();
|
|
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2));
|
|
expect(tester.getSize(find.byKey(key2)), const Size(228.0, 34.0));
|
|
});
|
|
|
|
testWidgets('Material3 - Tap target size is configurable', (WidgetTester tester) async {
|
|
Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) {
|
|
return boilerplate(
|
|
child: ToggleButtons(
|
|
key: key,
|
|
tapTargetSize: tapTargetSize,
|
|
constraints: const BoxConstraints(minWidth: 32.0, minHeight: 32.0),
|
|
isSelected: const <bool>[false, true, false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First'), Text('Second'), Text('Third')],
|
|
),
|
|
);
|
|
}
|
|
|
|
final Key key1 = UniqueKey();
|
|
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1));
|
|
expect(tester.getSize(find.byKey(key1)), const Size(232.0, 48.0));
|
|
|
|
final Key key2 = UniqueKey();
|
|
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2));
|
|
expect(tester.getSize(find.byKey(key2)), const Size(232.0, 34.0));
|
|
});
|
|
|
|
testWidgets('Tap target size is configurable for vertical axis', (WidgetTester tester) async {
|
|
Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) {
|
|
return boilerplate(
|
|
child: ToggleButtons(
|
|
key: key,
|
|
tapTargetSize: tapTargetSize,
|
|
constraints: const BoxConstraints(minWidth: 32.0, minHeight: 32.0),
|
|
direction: Axis.vertical,
|
|
isSelected: const <bool>[false, true, false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('1'), Text('2'), Text('3')],
|
|
),
|
|
);
|
|
}
|
|
|
|
final Key key1 = UniqueKey();
|
|
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.padded, key1));
|
|
expect(tester.getSize(find.byKey(key1)), const Size(48.0, 100.0));
|
|
|
|
final Key key2 = UniqueKey();
|
|
await tester.pumpWidget(buildFrame(MaterialTapTargetSize.shrinkWrap, key2));
|
|
expect(tester.getSize(find.byKey(key2)), const Size(34.0, 100.0));
|
|
});
|
|
|
|
// Regression test for https://github.com/flutter/flutter/issues/73725
|
|
testWidgets('Material2 - Border radius paint test when there is only one button', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final theme = ThemeData(useMaterial3: false);
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
theme: theme,
|
|
child: RepaintBoundary(
|
|
child: ToggleButtons(
|
|
borderRadius: const BorderRadius.all(Radius.circular(7.0)),
|
|
isSelected: const <bool>[true],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First child')],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
// The only button should be laid out at the center of the screen.
|
|
expect(tester.getCenter(find.text('First child')), const Offset(400.0, 300.0));
|
|
|
|
final List<RenderObject> toggleButtonRenderObject = tester.allRenderObjects
|
|
.where((RenderObject object) {
|
|
return object.runtimeType.toString() == '_SelectToggleButtonRenderObject';
|
|
})
|
|
.toSet()
|
|
.toList();
|
|
|
|
// The first button paints the left, top and right sides with a path.
|
|
expect(
|
|
toggleButtonRenderObject[0],
|
|
paints
|
|
// physical model paints
|
|
..path()
|
|
// left side, top and right - enabled.
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: _defaultBorderWidth,
|
|
),
|
|
);
|
|
|
|
await expectLater(
|
|
find.byType(RepaintBoundary),
|
|
matchesGoldenFile('m2_toggle_buttons.oneButton.boardsPaint.png'),
|
|
);
|
|
});
|
|
|
|
testWidgets('Material3 - Border radius paint test when there is only one button', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final theme = ThemeData();
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: RepaintBoundary(
|
|
child: ToggleButtons(
|
|
borderRadius: const BorderRadius.all(Radius.circular(7.0)),
|
|
isSelected: const <bool>[true],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First child')],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
// The only button should be laid out at the center of the screen.
|
|
expect(tester.getCenter(find.text('First child')), const Offset(400.0, 300.0));
|
|
|
|
final List<RenderObject> toggleButtonRenderObject = tester.allRenderObjects
|
|
.where((RenderObject object) {
|
|
return object.runtimeType.toString() == '_SelectToggleButtonRenderObject';
|
|
})
|
|
.toSet()
|
|
.toList();
|
|
|
|
// The first button paints the left, top and right sides with a path.
|
|
expect(
|
|
toggleButtonRenderObject[0],
|
|
paints
|
|
// physical model paints
|
|
..path()
|
|
// left side, top and right - enabled.
|
|
..path(
|
|
style: PaintingStyle.stroke,
|
|
color: theme.colorScheme.onSurface.withOpacity(0.12),
|
|
strokeWidth: _defaultBorderWidth,
|
|
),
|
|
);
|
|
|
|
await expectLater(
|
|
find.byType(RepaintBoundary),
|
|
matchesGoldenFile('m3_toggle_buttons.oneButton.boardsPaint.png'),
|
|
);
|
|
});
|
|
|
|
testWidgets('Material2 - Border radius paint test when Radius.x or Radius.y equal 0.0', (
|
|
WidgetTester tester,
|
|
) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
theme: ThemeData(useMaterial3: false),
|
|
child: RepaintBoundary(
|
|
child: ToggleButtons(
|
|
borderRadius: const BorderRadius.only(
|
|
topRight: Radius.elliptical(10, 0),
|
|
topLeft: Radius.elliptical(0, 10),
|
|
bottomRight: Radius.elliptical(0, 10),
|
|
bottomLeft: Radius.elliptical(10, 0),
|
|
),
|
|
isSelected: const <bool>[true],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First child')],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
await expectLater(
|
|
find.byType(RepaintBoundary),
|
|
matchesGoldenFile('m2_toggle_buttons.oneButton.boardsPaint2.png'),
|
|
);
|
|
});
|
|
|
|
testWidgets('Material3 - Border radius paint test when Radius.x or Radius.y equal 0.0', (
|
|
WidgetTester tester,
|
|
) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: RepaintBoundary(
|
|
child: ToggleButtons(
|
|
borderRadius: const BorderRadius.only(
|
|
topRight: Radius.elliptical(10, 0),
|
|
topLeft: Radius.elliptical(0, 10),
|
|
bottomRight: Radius.elliptical(0, 10),
|
|
bottomLeft: Radius.elliptical(10, 0),
|
|
),
|
|
isSelected: const <bool>[true],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First child')],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
await expectLater(
|
|
find.byType(RepaintBoundary),
|
|
matchesGoldenFile('m3_toggle_buttons.oneButton.boardsPaint2.png'),
|
|
);
|
|
});
|
|
|
|
testWidgets('ToggleButtons implements debugFillProperties', (WidgetTester tester) async {
|
|
final builder = DiagnosticPropertiesBuilder();
|
|
|
|
ToggleButtons(
|
|
direction: Axis.vertical,
|
|
verticalDirection: VerticalDirection.up,
|
|
borderWidth: 3.0,
|
|
color: Colors.green,
|
|
selectedBorderColor: Colors.pink,
|
|
disabledColor: Colors.blue,
|
|
disabledBorderColor: Colors.yellow,
|
|
borderRadius: const BorderRadius.all(Radius.circular(7.0)),
|
|
isSelected: const <bool>[false, true, false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Text('First child'), Text('Second child'), Text('Third child')],
|
|
).debugFillProperties(builder);
|
|
|
|
final List<String> description = builder.properties
|
|
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
|
.map((DiagnosticsNode node) => node.toString())
|
|
.toList();
|
|
|
|
expect(description, <String>[
|
|
'Buttons are enabled',
|
|
'color: MaterialColor(primary value: ${const Color(0xff4caf50)})',
|
|
'disabledColor: MaterialColor(primary value: ${const Color(0xff2196f3)})',
|
|
'selectedBorderColor: MaterialColor(primary value: ${const Color(0xffe91e63)})',
|
|
'disabledBorderColor: MaterialColor(primary value: ${const Color(0xffffeb3b)})',
|
|
'borderRadius: BorderRadius.circular(7.0)',
|
|
'borderWidth: 3.0',
|
|
'direction: Axis.vertical',
|
|
'verticalDirection: VerticalDirection.up',
|
|
]);
|
|
});
|
|
|
|
testWidgets('ToggleButtons changes mouse cursor when the button is hovered', (
|
|
WidgetTester tester,
|
|
) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: MouseRegion(
|
|
cursor: SystemMouseCursors.forbidden,
|
|
child: ToggleButtons(
|
|
mouseCursor: SystemMouseCursors.text,
|
|
onPressed: (int index) {},
|
|
isSelected: const <bool>[false, true],
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
final TestGesture gesture = await tester.createGesture(
|
|
kind: PointerDeviceKind.mouse,
|
|
pointer: 1,
|
|
);
|
|
await gesture.addPointer(location: tester.getCenter(find.text('First child')));
|
|
|
|
await tester.pump();
|
|
|
|
expect(
|
|
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
|
SystemMouseCursors.text,
|
|
);
|
|
|
|
// Test default cursor
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: MouseRegion(
|
|
cursor: SystemMouseCursors.forbidden,
|
|
child: ToggleButtons(
|
|
onPressed: (int index) {},
|
|
isSelected: const <bool>[false, true],
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
|
kIsWeb ? SystemMouseCursors.click : SystemMouseCursors.basic,
|
|
);
|
|
|
|
// Test default cursor when disabled
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: MouseRegion(
|
|
cursor: SystemMouseCursors.forbidden,
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[false, true],
|
|
children: const <Widget>[Text('First child'), Text('Second child')],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
|
|
SystemMouseCursors.basic,
|
|
);
|
|
});
|
|
|
|
testWidgets('ToggleButtons focus, hover, and highlight elevations are 0', (
|
|
WidgetTester tester,
|
|
) async {
|
|
final focusNodes = <FocusNode>[FocusNode(), FocusNode()];
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[true, false],
|
|
onPressed: (int index) {},
|
|
focusNodes: focusNodes,
|
|
children: const <Widget>[Text('one'), Text('two')],
|
|
),
|
|
),
|
|
);
|
|
|
|
double toggleButtonElevation(String text) {
|
|
return tester.widget<Material>(find.widgetWithText(Material, text).first).elevation;
|
|
}
|
|
|
|
// Default toggle button elevation
|
|
expect(toggleButtonElevation('one'), 0); // highlighted
|
|
expect(toggleButtonElevation('two'), 0); // not highlighted
|
|
|
|
// Hovered button elevation
|
|
final TestGesture hoverGesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
|
|
await hoverGesture.addPointer();
|
|
await hoverGesture.moveTo(tester.getCenter(find.text('one')));
|
|
await tester.pumpAndSettle();
|
|
expect(toggleButtonElevation('one'), 0);
|
|
await hoverGesture.moveTo(tester.getCenter(find.text('two')));
|
|
await tester.pumpAndSettle();
|
|
expect(toggleButtonElevation('two'), 0);
|
|
|
|
// Focused button elevation
|
|
focusNodes[0].requestFocus();
|
|
await tester.pumpAndSettle();
|
|
expect(focusNodes[0].hasFocus, isTrue);
|
|
expect(focusNodes[1].hasFocus, isFalse);
|
|
expect(toggleButtonElevation('one'), 0);
|
|
focusNodes[1].requestFocus();
|
|
await tester.pumpAndSettle();
|
|
expect(focusNodes[0].hasFocus, isFalse);
|
|
expect(focusNodes[1].hasFocus, isTrue);
|
|
expect(toggleButtonElevation('two'), 0);
|
|
|
|
await hoverGesture.removePointer();
|
|
|
|
for (final n in focusNodes) {
|
|
n.dispose();
|
|
}
|
|
});
|
|
|
|
testWidgets('Toggle buttons height matches MaterialTapTargetSize.padded height', (
|
|
WidgetTester tester,
|
|
) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[false, false, false],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Icon(Icons.check), Icon(Icons.access_alarm), Icon(Icons.cake)],
|
|
),
|
|
),
|
|
);
|
|
|
|
final Rect firstRect = tester.getRect(find.byType(TextButton).at(0));
|
|
expect(firstRect.height, 48.0);
|
|
final Rect secondRect = tester.getRect(find.byType(TextButton).at(1));
|
|
expect(secondRect.height, 48.0);
|
|
final Rect thirdRect = tester.getRect(find.byType(TextButton).at(2));
|
|
expect(thirdRect.height, 48.0);
|
|
});
|
|
|
|
testWidgets('Toggle buttons constraints size does not affect minimum input padding', (
|
|
WidgetTester tester,
|
|
) async {
|
|
// Regression test for https://github.com/flutter/flutter/issues/97302
|
|
final semantics = SemanticsTester(tester);
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[false, false, false],
|
|
onPressed: (int index) {},
|
|
constraints: const BoxConstraints.tightFor(width: 86, height: 32),
|
|
children: const <Widget>[Icon(Icons.check), Icon(Icons.access_alarm), Icon(Icons.cake)],
|
|
),
|
|
),
|
|
);
|
|
|
|
// Button's height is constrained to `32.0`.
|
|
final Rect firstRect = tester.getRect(find.byType(TextButton).at(0));
|
|
expect(firstRect.height, 32.0);
|
|
final Rect secondRect = tester.getRect(find.byType(TextButton).at(1));
|
|
expect(secondRect.height, 32.0);
|
|
final Rect thirdRect = tester.getRect(find.byType(TextButton).at(2));
|
|
expect(thirdRect.height, 32.0);
|
|
|
|
// While button's height is constrained to `32.0`, semantic node height
|
|
// should remain `48.0`, matching `MaterialTapTargetSize.padded` height (default).
|
|
expect(
|
|
semantics,
|
|
hasSemantics(
|
|
TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
flags: <SemanticsFlag>[
|
|
SemanticsFlag.isButton,
|
|
SemanticsFlag.isEnabled,
|
|
SemanticsFlag.hasEnabledState,
|
|
SemanticsFlag.hasCheckedState,
|
|
SemanticsFlag.isFocusable,
|
|
],
|
|
actions: <SemanticsAction>[SemanticsAction.tap, SemanticsAction.focus],
|
|
rect: const Rect.fromLTRB(0.0, 0.0, 87.0, 48.0),
|
|
),
|
|
TestSemantics(
|
|
flags: <SemanticsFlag>[
|
|
SemanticsFlag.isButton,
|
|
SemanticsFlag.isEnabled,
|
|
SemanticsFlag.hasEnabledState,
|
|
SemanticsFlag.hasCheckedState,
|
|
SemanticsFlag.isFocusable,
|
|
],
|
|
actions: <SemanticsAction>[SemanticsAction.tap, SemanticsAction.focus],
|
|
rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0),
|
|
),
|
|
TestSemantics(
|
|
flags: <SemanticsFlag>[
|
|
SemanticsFlag.isButton,
|
|
SemanticsFlag.isEnabled,
|
|
SemanticsFlag.hasEnabledState,
|
|
SemanticsFlag.hasCheckedState,
|
|
SemanticsFlag.isFocusable,
|
|
],
|
|
actions: <SemanticsAction>[SemanticsAction.tap, SemanticsAction.focus],
|
|
rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0),
|
|
),
|
|
],
|
|
),
|
|
ignoreId: true,
|
|
ignoreRect: true,
|
|
ignoreTransform: true,
|
|
),
|
|
);
|
|
|
|
semantics.dispose();
|
|
});
|
|
|
|
testWidgets('Toggle buttons have correct semantics', (WidgetTester tester) async {
|
|
final semantics = SemanticsTester(tester);
|
|
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[false, true],
|
|
onPressed: (int index) {},
|
|
children: const <Widget>[Icon(Icons.check), Icon(Icons.access_alarm)],
|
|
),
|
|
),
|
|
);
|
|
|
|
expect(
|
|
semantics,
|
|
hasSemantics(
|
|
TestSemantics.root(
|
|
children: <TestSemantics>[
|
|
TestSemantics(
|
|
flags: <SemanticsFlag>[
|
|
SemanticsFlag.isButton,
|
|
SemanticsFlag.isEnabled,
|
|
SemanticsFlag.hasEnabledState,
|
|
SemanticsFlag.hasCheckedState,
|
|
SemanticsFlag.isFocusable,
|
|
],
|
|
actions: <SemanticsAction>[SemanticsAction.tap, SemanticsAction.focus],
|
|
),
|
|
TestSemantics(
|
|
flags: <SemanticsFlag>[
|
|
SemanticsFlag.isButton,
|
|
SemanticsFlag.isEnabled,
|
|
SemanticsFlag.hasEnabledState,
|
|
SemanticsFlag.isChecked,
|
|
SemanticsFlag.hasCheckedState,
|
|
SemanticsFlag.isFocusable,
|
|
],
|
|
actions: <SemanticsAction>[SemanticsAction.tap, SemanticsAction.focus],
|
|
),
|
|
],
|
|
),
|
|
ignoreId: true,
|
|
ignoreRect: true,
|
|
ignoreTransform: true,
|
|
),
|
|
);
|
|
|
|
semantics.dispose();
|
|
});
|
|
|
|
testWidgets('ToggleButtons does not crash at zero area', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
boilerplate(
|
|
child: Center(
|
|
child: SizedBox.shrink(
|
|
child: ToggleButtons(
|
|
isSelected: const <bool>[true],
|
|
children: const <Widget>[Text('X')],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
expect(tester.getSize(find.byType(ToggleButtons)), Size.zero);
|
|
});
|
|
}
|