blob: f7bb7768b3d6efe68b39a7f442afa4c5a5c20884 [file] [log] [blame]
// 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/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() {
testWidgetsWithLeakTracking('ButtonBar default control smoketest', (WidgetTester tester) async {
await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.ltr,
child: ButtonBar(),
),
);
});
group('alignment', () {
testWidgetsWithLeakTracking('default alignment is MainAxisAlignment.end', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: ButtonBar(
children: <Widget>[
SizedBox(width: 10.0, height: 10.0),
],
),
),
);
final Finder child = find.byType(SizedBox);
// Should be positioned to the right of the bar,
expect(tester.getRect(child).left, 782.0); // bar width - default padding - 10
expect(tester.getRect(child).right, 792.0); // bar width - default padding
});
testWidgetsWithLeakTracking('ButtonBarTheme.alignment overrides default', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: ButtonBarTheme(
data: ButtonBarThemeData(
alignment: MainAxisAlignment.center,
),
child: ButtonBar(
children: <Widget>[
SizedBox(width: 10.0, height: 10.0),
],
),
),
),
);
final Finder child = find.byType(SizedBox);
// Should be positioned in the center
expect(tester.getRect(child).left, 395.0); // (bar width - padding) / 2 - 10 / 2
expect(tester.getRect(child).right, 405.0); // (bar width - padding) / 2 - 10 / 2 + 10
});
testWidgetsWithLeakTracking('ButtonBar.alignment overrides ButtonBarTheme.alignment and default', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: ButtonBarTheme(
data: ButtonBarThemeData(
alignment: MainAxisAlignment.center,
),
child: ButtonBar(
alignment: MainAxisAlignment.start,
children: <Widget>[
SizedBox(width: 10.0, height: 10.0),
],
),
),
),
);
final Finder child = find.byType(SizedBox);
// Should be positioned on the left
expect(tester.getRect(child).left, 8.0); // padding
expect(tester.getRect(child).right, 18.0); // padding + 10
});
});
group('mainAxisSize', () {
testWidgetsWithLeakTracking('Default mainAxisSize is MainAxisSize.max', (WidgetTester tester) async {
const Key buttonBarKey = Key('row');
const Key child0Key = Key('child0');
const Key child1Key = Key('child1');
const Key child2Key = Key('child2');
await tester.pumpWidget(
const MaterialApp(
home: Center(
child: ButtonBar(
key: buttonBarKey,
// buttonPadding set to zero to simplify test calculations.
buttonPadding: EdgeInsets.zero,
children: <Widget>[
SizedBox(key: child0Key, width: 100.0, height: 100.0),
SizedBox(key: child1Key, width: 100.0, height: 100.0),
SizedBox(key: child2Key, width: 100.0, height: 100.0),
],
),
),
),
);
// ButtonBar should take up all the space it is provided by its parent.
final Rect buttonBarRect = tester.getRect(find.byKey(buttonBarKey));
expect(buttonBarRect.size.width, equals(800.0));
expect(buttonBarRect.size.height, equals(100.0));
// The children of [ButtonBar] are aligned by [MainAxisAlignment.end] by
// default.
Rect childRect;
childRect = tester.getRect(find.byKey(child0Key));
expect(childRect.size.width, equals(100.0));
expect(childRect.size.height, equals(100.0));
expect(childRect.right, 800.0 - 200.0);
childRect = tester.getRect(find.byKey(child1Key));
expect(childRect.size.width, equals(100.0));
expect(childRect.size.height, equals(100.0));
expect(childRect.right, 800.0 - 100.0);
childRect = tester.getRect(find.byKey(child2Key));
expect(childRect.size.width, equals(100.0));
expect(childRect.size.height, equals(100.0));
expect(childRect.right, 800.0);
});
testWidgetsWithLeakTracking('ButtonBarTheme.mainAxisSize overrides default', (WidgetTester tester) async {
const Key buttonBarKey = Key('row');
const Key child0Key = Key('child0');
const Key child1Key = Key('child1');
const Key child2Key = Key('child2');
await tester.pumpWidget(
const MaterialApp(
home: ButtonBarTheme(
data: ButtonBarThemeData(
mainAxisSize: MainAxisSize.min,
),
child: Center(
child: ButtonBar(
key: buttonBarKey,
// buttonPadding set to zero to simplify test calculations.
buttonPadding: EdgeInsets.zero,
children: <Widget>[
SizedBox(key: child0Key, width: 100.0, height: 100.0),
SizedBox(key: child1Key, width: 100.0, height: 100.0),
SizedBox(key: child2Key, width: 100.0, height: 100.0),
],
),
),
),
),
);
// ButtonBar should take up minimum space it requires.
final Rect buttonBarRect = tester.getRect(find.byKey(buttonBarKey));
expect(buttonBarRect.size.width, equals(300.0));
expect(buttonBarRect.size.height, equals(100.0));
Rect childRect;
childRect = tester.getRect(find.byKey(child0Key));
expect(childRect.size.width, equals(100.0));
expect(childRect.size.height, equals(100.0));
// Should be a center aligned because of [Center] widget.
// First child is on the left side of the button bar.
expect(childRect.left, (800.0 - buttonBarRect.width) / 2.0);
childRect = tester.getRect(find.byKey(child1Key));
expect(childRect.size.width, equals(100.0));
expect(childRect.size.height, equals(100.0));
// Should be a center aligned because of [Center] widget.
// Second child is on the center the button bar.
expect(childRect.left, ((800.0 - buttonBarRect.width) / 2.0) + 100.0);
childRect = tester.getRect(find.byKey(child2Key));
expect(childRect.size.width, equals(100.0));
expect(childRect.size.height, equals(100.0));
// Should be a center aligned because of [Center] widget.
// Third child is on the right side of the button bar.
expect(childRect.left, ((800.0 - buttonBarRect.width) / 2.0) + 200.0);
});
testWidgetsWithLeakTracking('ButtonBar.mainAxisSize overrides ButtonBarTheme.mainAxisSize and default', (WidgetTester tester) async {
const Key buttonBarKey = Key('row');
const Key child0Key = Key('child0');
const Key child1Key = Key('child1');
const Key child2Key = Key('child2');
await tester.pumpWidget(
const MaterialApp(
home: ButtonBarTheme(
data: ButtonBarThemeData(
mainAxisSize: MainAxisSize.min,
),
child: Center(
child: ButtonBar(
key: buttonBarKey,
// buttonPadding set to zero to simplify test calculations.
buttonPadding: EdgeInsets.zero,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
SizedBox(key: child0Key, width: 100.0, height: 100.0),
SizedBox(key: child1Key, width: 100.0, height: 100.0),
SizedBox(key: child2Key, width: 100.0, height: 100.0),
],
),
),
),
),
);
// ButtonBar should take up all the space it is provided by its parent.
final Rect buttonBarRect = tester.getRect(find.byKey(buttonBarKey));
expect(buttonBarRect.size.width, equals(800.0));
expect(buttonBarRect.size.height, equals(100.0));
// The children of [ButtonBar] are aligned by [MainAxisAlignment.end] by
// default.
Rect childRect;
childRect = tester.getRect(find.byKey(child0Key));
expect(childRect.size.width, equals(100.0));
expect(childRect.size.height, equals(100.0));
expect(childRect.right, 800.0 - 200.0);
childRect = tester.getRect(find.byKey(child1Key));
expect(childRect.size.width, equals(100.0));
expect(childRect.size.height, equals(100.0));
expect(childRect.right, 800.0 - 100.0);
childRect = tester.getRect(find.byKey(child2Key));
expect(childRect.size.width, equals(100.0));
expect(childRect.size.height, equals(100.0));
expect(childRect.right, 800.0);
});
});
group('button properties override ButtonTheme', () {
testWidgetsWithLeakTracking('default button properties override ButtonTheme properties', (WidgetTester tester) async {
late BuildContext capturedContext;
await tester.pumpWidget(
MaterialApp(
home: ButtonBar(
children: <Widget>[
Builder(builder: (BuildContext context) {
capturedContext = context;
return Container();
}),
],
),
),
);
final ButtonThemeData buttonTheme = ButtonTheme.of(capturedContext);
expect(buttonTheme.textTheme, equals(ButtonTextTheme.primary));
expect(buttonTheme.minWidth, equals(64.0));
expect(buttonTheme.height, equals(36.0));
expect(buttonTheme.padding, equals(const EdgeInsets.symmetric(horizontal: 8.0)));
expect(buttonTheme.alignedDropdown, equals(false));
expect(buttonTheme.layoutBehavior, equals(ButtonBarLayoutBehavior.padded));
});
testWidgetsWithLeakTracking('ButtonBarTheme button properties override defaults and ButtonTheme properties', (WidgetTester tester) async {
late BuildContext capturedContext;
await tester.pumpWidget(
MaterialApp(
home: ButtonBarTheme(
data: const ButtonBarThemeData(
buttonTextTheme: ButtonTextTheme.primary,
buttonMinWidth: 42.0,
buttonHeight: 84.0,
buttonPadding: EdgeInsets.fromLTRB(10, 20, 30, 40),
buttonAlignedDropdown: true,
layoutBehavior: ButtonBarLayoutBehavior.constrained,
),
child: ButtonBar(
children: <Widget>[
Builder(builder: (BuildContext context) {
capturedContext = context;
return Container();
}),
],
),
),
),
);
final ButtonThemeData buttonTheme = ButtonTheme.of(capturedContext);
expect(buttonTheme.textTheme, equals(ButtonTextTheme.primary));
expect(buttonTheme.minWidth, equals(42.0));
expect(buttonTheme.height, equals(84.0));
expect(buttonTheme.padding, equals(const EdgeInsets.fromLTRB(10, 20, 30, 40)));
expect(buttonTheme.alignedDropdown, equals(true));
expect(buttonTheme.layoutBehavior, equals(ButtonBarLayoutBehavior.constrained));
});
testWidgetsWithLeakTracking('ButtonBar button properties override ButtonBarTheme, defaults and ButtonTheme properties', (WidgetTester tester) async {
late BuildContext capturedContext;
await tester.pumpWidget(
MaterialApp(
home: ButtonBarTheme(
data: const ButtonBarThemeData(
buttonTextTheme: ButtonTextTheme.accent,
buttonMinWidth: 4242.0,
buttonHeight: 8484.0,
buttonPadding: EdgeInsets.fromLTRB(50, 60, 70, 80),
buttonAlignedDropdown: false,
layoutBehavior: ButtonBarLayoutBehavior.padded,
),
child: ButtonBar(
buttonTextTheme: ButtonTextTheme.primary,
buttonMinWidth: 42.0,
buttonHeight: 84.0,
buttonPadding: const EdgeInsets.fromLTRB(10, 20, 30, 40),
buttonAlignedDropdown: true,
layoutBehavior: ButtonBarLayoutBehavior.constrained,
children: <Widget>[
Builder(builder: (BuildContext context) {
capturedContext = context;
return Container();
}),
],
),
),
),
);
final ButtonThemeData buttonTheme = ButtonTheme.of(capturedContext);
expect(buttonTheme.textTheme, equals(ButtonTextTheme.primary));
expect(buttonTheme.minWidth, equals(42.0));
expect(buttonTheme.height, equals(84.0));
expect(buttonTheme.padding, equals(const EdgeInsets.fromLTRB(10, 20, 30, 40)));
expect(buttonTheme.alignedDropdown, equals(true));
expect(buttonTheme.layoutBehavior, equals(ButtonBarLayoutBehavior.constrained));
});
});
group('layoutBehavior', () {
testWidgets('ButtonBar has a min height of 52 when using ButtonBarLayoutBehavior.constrained', (WidgetTester tester) async {
await tester.pumpWidget(
const SingleChildScrollView(
child: ListBody(
children: <Widget>[
Directionality(
textDirection: TextDirection.ltr,
child: ButtonBar(
layoutBehavior: ButtonBarLayoutBehavior.constrained,
children: <Widget>[
SizedBox(width: 10.0, height: 10.0),
],
),
),
],
),
),
);
final Finder buttonBar = find.byType(ButtonBar);
expect(tester.getBottomRight(buttonBar).dy - tester.getTopRight(buttonBar).dy, 52.0);
});
testWidgets('ButtonBar has padding applied when using ButtonBarLayoutBehavior.padded', (WidgetTester tester) async {
await tester.pumpWidget(
const SingleChildScrollView(
child: ListBody(
children: <Widget>[
Directionality(
textDirection: TextDirection.ltr,
child: ButtonBar(
layoutBehavior: ButtonBarLayoutBehavior.padded,
children: <Widget>[
SizedBox(width: 10.0, height: 10.0),
],
),
),
],
),
),
);
final Finder buttonBar = find.byType(ButtonBar);
expect(tester.getBottomRight(buttonBar).dy - tester.getTopRight(buttonBar).dy, 26.0);
});
});
group("ButtonBar's children wrap when they overflow horizontally", () {
testWidgetsWithLeakTracking("ButtonBar's children wrap when buttons overflow", (WidgetTester tester) async {
final Key keyOne = UniqueKey();
final Key keyTwo = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: ButtonBar(
children: <Widget>[
SizedBox(key: keyOne, height: 50.0, width: 800.0),
SizedBox(key: keyTwo, height: 50.0, width: 800.0),
],
),
),
);
// Second [Container] should wrap around to the next column since
// they take up max width constraint.
final Rect containerOneRect = tester.getRect(find.byKey(keyOne));
final Rect containerTwoRect = tester.getRect(find.byKey(keyTwo));
expect(containerOneRect.bottom, containerTwoRect.top);
expect(containerOneRect.left, containerTwoRect.left);
});
testWidgetsWithLeakTracking(
"ButtonBar's children overflow defaults - MainAxisAlignment.end", (WidgetTester tester) async {
final Key keyOne = UniqueKey();
final Key keyTwo = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: ButtonBar(
// Set padding to zero to align buttons with edge of button bar.
buttonPadding: EdgeInsets.zero,
children: <Widget>[
SizedBox(key: keyOne, height: 50.0, width: 500.0),
SizedBox(key: keyTwo, height: 50.0, width: 500.0),
],
),
),
);
final Rect buttonBarRect = tester.getRect(find.byType(ButtonBar));
final Rect containerOneRect = tester.getRect(find.byKey(keyOne));
final Rect containerTwoRect = tester.getRect(find.byKey(keyTwo));
// Second [Container] should wrap around to the next row.
expect(containerOneRect.bottom, containerTwoRect.top);
// Second [Container] should align to the start of the ButtonBar.
expect(containerOneRect.right, containerTwoRect.right);
expect(containerOneRect.right, buttonBarRect.right);
},
);
testWidgetsWithLeakTracking("ButtonBar's children overflow - MainAxisAlignment.start", (WidgetTester tester) async {
final Key keyOne = UniqueKey();
final Key keyTwo = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: ButtonBar(
alignment: MainAxisAlignment.start,
// Set padding to zero to align buttons with edge of button bar.
buttonPadding: EdgeInsets.zero,
children: <Widget>[
SizedBox(key: keyOne, height: 50.0, width: 500.0),
SizedBox(key: keyTwo, height: 50.0, width: 500.0),
],
),
),
);
final Rect buttonBarRect = tester.getRect(find.byType(ButtonBar));
final Rect containerOneRect = tester.getRect(find.byKey(keyOne));
final Rect containerTwoRect = tester.getRect(find.byKey(keyTwo));
// Second [Container] should wrap around to the next row.
expect(containerOneRect.bottom, containerTwoRect.top);
// [Container]s should align to the end of the ButtonBar.
expect(containerOneRect.left, containerTwoRect.left);
expect(containerOneRect.left, buttonBarRect.left);
});
testWidgetsWithLeakTracking("ButtonBar's children overflow - MainAxisAlignment.center", (WidgetTester tester) async {
final Key keyOne = UniqueKey();
final Key keyTwo = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: ButtonBar(
alignment: MainAxisAlignment.center,
// Set padding to zero to align buttons with edge of button bar.
buttonPadding: EdgeInsets.zero,
children: <Widget>[
SizedBox(key: keyOne, height: 50.0, width: 500.0),
SizedBox(key: keyTwo, height: 50.0, width: 500.0),
],
),
),
);
final Rect buttonBarRect = tester.getRect(find.byType(ButtonBar));
final Rect containerOneRect = tester.getRect(find.byKey(keyOne));
final Rect containerTwoRect = tester.getRect(find.byKey(keyTwo));
// Second [Container] should wrap around to the next row.
expect(containerOneRect.bottom, containerTwoRect.top);
// [Container]s should center themselves in the ButtonBar.
expect(containerOneRect.center.dx, containerTwoRect.center.dx);
expect(containerOneRect.center.dx, buttonBarRect.center.dx);
});
testWidgetsWithLeakTracking(
"ButtonBar's children default to MainAxisAlignment.start for horizontal "
'alignment when overflowing in spaceBetween, spaceAround and spaceEvenly '
'cases when overflowing.', (WidgetTester tester) async {
final Key keyOne = UniqueKey();
final Key keyTwo = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: ButtonBar(
alignment: MainAxisAlignment.spaceEvenly,
// Set padding to zero to align buttons with edge of button bar.
buttonPadding: EdgeInsets.zero,
children: <Widget>[
SizedBox(key: keyOne, height: 50.0, width: 500.0),
SizedBox(key: keyTwo, height: 50.0, width: 500.0),
],
),
),
);
Rect buttonBarRect = tester.getRect(find.byType(ButtonBar));
Rect containerOneRect = tester.getRect(find.byKey(keyOne));
Rect containerTwoRect = tester.getRect(find.byKey(keyTwo));
// Second [Container] should wrap around to the next row.
expect(containerOneRect.bottom, containerTwoRect.top);
// Should align horizontally to the start of the button bar.
expect(containerOneRect.left, containerTwoRect.left);
expect(containerOneRect.left, buttonBarRect.left);
await tester.pumpWidget(
MaterialApp(
home: ButtonBar(
alignment: MainAxisAlignment.spaceAround,
// Set padding to zero to align buttons with edge of button bar.
buttonPadding: EdgeInsets.zero,
children: <Widget>[
SizedBox(key: keyOne, height: 50.0, width: 500.0),
SizedBox(key: keyTwo, height: 50.0, width: 500.0),
],
),
),
);
buttonBarRect = tester.getRect(find.byType(ButtonBar));
containerOneRect = tester.getRect(find.byKey(keyOne));
containerTwoRect = tester.getRect(find.byKey(keyTwo));
// Second [Container] should wrap around to the next row.
expect(containerOneRect.bottom, containerTwoRect.top);
// Should align horizontally to the start of the button bar.
expect(containerOneRect.left, containerTwoRect.left);
expect(containerOneRect.left, buttonBarRect.left);
},
);
testWidgetsWithLeakTracking(
"ButtonBar's children respects verticalDirection when overflowing",
(WidgetTester tester) async {
final Key keyOne = UniqueKey();
final Key keyTwo = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: ButtonBar(
alignment: MainAxisAlignment.center,
// Set padding to zero to align buttons with edge of button bar.
buttonPadding: EdgeInsets.zero,
// Set the vertical direction to start from the bottom and lay
// out upwards.
overflowDirection: VerticalDirection.up,
children: <Widget>[
SizedBox(key: keyOne, height: 50.0, width: 500.0),
SizedBox(key: keyTwo, height: 50.0, width: 500.0),
],
),
),
);
final Rect containerOneRect = tester.getRect(find.byKey(keyOne));
final Rect containerTwoRect = tester.getRect(find.byKey(keyTwo));
// Second [Container] should appear above first container.
expect(containerTwoRect.bottom, lessThanOrEqualTo(containerOneRect.top));
},
);
testWidgetsWithLeakTracking(
'ButtonBar has no spacing by default when overflowing',
(WidgetTester tester) async {
final Key keyOne = UniqueKey();
final Key keyTwo = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: ButtonBar(
alignment: MainAxisAlignment.center,
// Set padding to zero to align buttons with edge of button bar.
buttonPadding: EdgeInsets.zero,
children: <Widget>[
SizedBox(key: keyOne, height: 50.0, width: 500.0),
SizedBox(key: keyTwo, height: 50.0, width: 500.0),
],
),
),
);
final Rect containerOneRect = tester.getRect(find.byKey(keyOne));
final Rect containerTwoRect = tester.getRect(find.byKey(keyTwo));
expect(containerOneRect.bottom, containerTwoRect.top);
},
);
testWidgetsWithLeakTracking(
"ButtonBar's children respects overflowButtonSpacing when overflowing",
(WidgetTester tester) async {
final Key keyOne = UniqueKey();
final Key keyTwo = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: ButtonBar(
alignment: MainAxisAlignment.center,
// Set padding to zero to align buttons with edge of button bar.
buttonPadding: EdgeInsets.zero,
// Set the overflow button spacing to ensure add some space between
// buttons in an overflow case.
overflowButtonSpacing: 10.0,
children: <Widget>[
SizedBox(key: keyOne, height: 50.0, width: 500.0),
SizedBox(key: keyTwo, height: 50.0, width: 500.0),
],
),
),
);
final Rect containerOneRect = tester.getRect(find.byKey(keyOne));
final Rect containerTwoRect = tester.getRect(find.byKey(keyTwo));
expect(containerOneRect.bottom, containerTwoRect.top - 10.0);
},
);
});
testWidgetsWithLeakTracking('_RenderButtonBarRow.constraints does not work before layout', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(home: ButtonBar()),
Duration.zero,
EnginePhase.build,
);
final Finder buttonBar = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_ButtonBarRow');
final RenderBox renderButtonBar = tester.renderObject(buttonBar) as RenderBox;
expect(renderButtonBar.debugNeedsLayout, isTrue);
expect(() => renderButtonBar.constraints, throwsStateError);
});
}