// 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/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('OverflowBar documented defaults', (WidgetTester tester) async { const OverflowBar bar = OverflowBar(); expect(bar.spacing, 0); expect(bar.alignment, null); expect(bar.overflowSpacing, 0); expect(bar.overflowDirection, VerticalDirection.down); expect(bar.textDirection, null); expect(bar.clipBehavior, Clip.none); expect(bar.children, const <Widget>[]); }); testWidgets('Empty OverflowBar', (WidgetTester tester) async { const Size size = Size(16, 24); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Center( child: ConstrainedBox( constraints: BoxConstraints.tight(size), child: const OverflowBar(), ), ), ), ); expect(tester.getSize(find.byType(OverflowBar)), size); await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Center( child: OverflowBar(), ), ), ); expect(tester.getSize(find.byType(OverflowBar)), Size.zero); }); testWidgets('OverflowBar horizontal layout', (WidgetTester tester) async { final Key child1Key = UniqueKey(); final Key child2Key = UniqueKey(); final Key child3Key = UniqueKey(); Widget buildFrame({ required double spacing, required TextDirection textDirection }) { return Directionality( textDirection: textDirection, child: Align( alignment: Alignment.topLeft, child: OverflowBar( spacing: spacing, children: <Widget>[ SizedBox(width: 48, height: 48, key: child1Key), SizedBox(width: 64, height: 64, key: child2Key), SizedBox(width: 32, height: 32, key: child3Key), ], ), ), ); } // Children are vertically centered, start at x=0 await tester.pumpWidget(buildFrame(spacing: 0, textDirection: TextDirection.ltr)); expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(0, 8, 48, 56)); expect(tester.getRect(find.byKey(child2Key)), const Rect.fromLTRB(48, 0, 112, 64)); expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(112, 16, 144, 48)); // Children are vertically centered, start at x=0 await tester.pumpWidget(buildFrame(spacing: 10, textDirection: TextDirection.ltr)); expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(0, 8, 48, 56)); expect(tester.getRect(find.byKey(child2Key)), const Rect.fromLTRB(10.0 + 48, 0, 10.0 + 112, 64)); expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(10.0 + 112 + 10.0, 16, 10.0 + 10.0 + 144, 48)); // Children appear in reverse order for RTL await tester.pumpWidget(buildFrame(spacing: 0, textDirection: TextDirection.rtl)); expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(0, 16, 32, 48)); expect(tester.getRect(find.byKey(child2Key)), const Rect.fromLTRB(32, 0, 96, 64)); expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(96, 8, 144, 56)); // Children appear in reverse order for RTL await tester.pumpWidget(buildFrame(spacing: 10, textDirection: TextDirection.rtl)); expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(0, 16, 32, 48)); expect(tester.getRect(find.byKey(child2Key)), const Rect.fromLTRB(10.0 + 32, 0, 10.0 + 96, 64)); expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(10.0 + 96 + 10.0, 8, 10.0 + 10.0 + 144, 56)); }); testWidgets('OverflowBar vertical layout', (WidgetTester tester) async { final Key child1Key = UniqueKey(); final Key child2Key = UniqueKey(); final Key child3Key = UniqueKey(); Widget buildFrame({ double overflowSpacing = 0, VerticalDirection overflowDirection = VerticalDirection.down, OverflowBarAlignment overflowAlignment = OverflowBarAlignment.start, TextDirection textDirection = TextDirection.ltr, }) { return Directionality( textDirection: textDirection, child: Align( alignment: Alignment.topLeft, child: ConstrainedBox( constraints: BoxConstraints.loose(const Size(100, double.infinity)), child: OverflowBar( overflowSpacing: overflowSpacing, overflowAlignment: overflowAlignment, overflowDirection: overflowDirection, children: <Widget>[ SizedBox(width: 48, height: 48, key: child1Key), SizedBox(width: 64, height: 64, key: child2Key), SizedBox(width: 32, height: 32, key: child3Key), ], ), ), ), ); } // Children are left aligned await tester.pumpWidget(buildFrame()); expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(0, 0, 48, 48)); expect(tester.getRect(find.byKey(child2Key)), const Rect.fromLTRB(0, 48, 64, 112)); expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(0, 112, 32, 144)); // Children are left aligned await tester.pumpWidget(buildFrame(overflowAlignment: OverflowBarAlignment.end, textDirection: TextDirection.rtl)); expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(0, 0, 48, 48)); expect(tester.getRect(find.byKey(child2Key)), const Rect.fromLTRB(0, 48, 64, 112)); expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(0, 112, 32, 144)); // Spaced children are left aligned await tester.pumpWidget(buildFrame(overflowSpacing: 10)); expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(0, 0, 48, 48)); expect(tester.getRect(find.byKey(child2Key)), const Rect.fromLTRB(0, 10.0 + 48, 64, 10.0 + 112)); expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(0, 10.0 + 112 + 10.0, 32, 10.0 + 10.0 + 144)); // Left-aligned children appear in reverse order for VerticalDirection.up await tester.pumpWidget(buildFrame(overflowDirection: VerticalDirection.up)); expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(0, 0, 32, 32)); expect(tester.getRect(find.byKey(child2Key)), const Rect.fromLTRB(0, 32, 64, 96)); expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(0, 96, 48, 144)); // Left-aligned spaced children appear in reverse order for VerticalDirection.up await tester.pumpWidget(buildFrame(overflowSpacing: 10, overflowDirection: VerticalDirection.up)); expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(0, 0, 32, 32)); expect(tester.getRect(find.byKey(child2Key)), const Rect.fromLTRB(0, 10.0 + 32, 64, 10.0 + 96)); expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(0, 10.0 + 10.0 + 96, 48, 10.0 + 10.0 + 144)); // Children are right aligned await tester.pumpWidget(buildFrame(overflowAlignment: OverflowBarAlignment.end)); expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(100.0 - 48, 0, 100, 48)); expect(tester.getRect(find.byKey(child2Key)), const Rect.fromLTRB(100.0 - 64, 48, 100, 112)); expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(100.0 - 32, 112, 100, 144)); // Children are right aligned await tester.pumpWidget(buildFrame(textDirection: TextDirection.rtl)); expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(100.0 - 48, 0, 100, 48)); expect(tester.getRect(find.byKey(child2Key)), const Rect.fromLTRB(100.0 - 64, 48, 100, 112)); expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(100.0 - 32, 112, 100, 144)); // Children are centered await tester.pumpWidget(buildFrame(overflowAlignment: OverflowBarAlignment.center)); expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(100.0/2.0 - 48/2, 0, 100.0/2.0 + 48/2, 48)); expect(tester.getRect(find.byKey(child2Key)), const Rect.fromLTRB(100.0/2.0 - 64/2, 48, 100.0/2.0 + 64/2, 112)); expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(100.0/2.0 - 32/2, 112, 100.0/2.0 + 32/2, 144)); }); testWidgets('OverflowBar intrinsic width', (WidgetTester tester) async { Widget buildFrame({ required double width }) { return Directionality( textDirection: TextDirection.ltr, child: Center( child: Container( width: width, alignment: Alignment.topLeft, child: const IntrinsicWidth( child: OverflowBar( spacing: 4, overflowSpacing: 8, children: <Widget>[ SizedBox(width: 48, height: 50), SizedBox(width: 64, height: 25), SizedBox(width: 32, height: 75), ], ), ), ), ), ); } await tester.pumpWidget(buildFrame(width: 800)); expect(tester.getSize(find.byType(OverflowBar)).width, 152); // 152 = 48 + 4 + 64 + 4 + 32 await tester.pumpWidget(buildFrame(width: 150)); expect(tester.getSize(find.byType(OverflowBar)).width, 150); }); testWidgets('OverflowBar intrinsic height', (WidgetTester tester) async { Widget buildFrame({ required double maxWidth }) { return Directionality( textDirection: TextDirection.ltr, child: Center( child: Container( width: maxWidth, alignment: Alignment.topLeft, child: const IntrinsicHeight( child: OverflowBar( spacing: 4, overflowSpacing: 8, children: <Widget>[ SizedBox(width: 48, height: 50), SizedBox(width: 64, height: 25), SizedBox(width: 32, height: 75), ], ), ), ), ), ); } await tester.pumpWidget(buildFrame(maxWidth: 800)); expect(tester.getSize(find.byType(OverflowBar)).height, 75); // 75 = max(50, 25, 75) await tester.pumpWidget(buildFrame(maxWidth: 150)); expect(tester.getSize(find.byType(OverflowBar)).height, 166); // 166 = 50 + 8 + 25 + 8 + 75 }); testWidgets('OverflowBar is wider that its intrinsic width', (WidgetTester tester) async { final Key key0 = UniqueKey(); final Key key1 = UniqueKey(); final Key key2 = UniqueKey(); Widget buildFrame(TextDirection textDirection) { return Directionality( textDirection: textDirection, child: SizedBox( width: 800, // intrinsic width = 50 + 10 + 60 + 10 + 70 = 200 child: OverflowBar( spacing: 10, children: <Widget>[ SizedBox(key: key0, width: 50, height: 50), SizedBox(key: key1, width: 60, height: 50), SizedBox(key: key2, width: 70, height: 50), ], ), ), ); } await tester.pumpWidget(buildFrame(TextDirection.ltr)); expect(tester.getSize(find.byType(OverflowBar)), const Size(800.0, 600.0)); expect(tester.getTopLeft(find.byKey(key0)).dx, 0); expect(tester.getTopLeft(find.byKey(key1)).dx, 60); expect(tester.getTopLeft(find.byKey(key2)).dx, 130); await tester.pumpWidget(buildFrame(TextDirection.rtl)); expect(tester.getSize(find.byType(OverflowBar)), const Size(800.0, 600.0)); expect(tester.getTopLeft(find.byKey(key0)).dx, 750); expect(tester.getTopLeft(find.byKey(key1)).dx, 680); expect(tester.getTopLeft(find.byKey(key2)).dx, 600); }); testWidgets('OverflowBar with alignment should match Row with mainAxisAlignment', (WidgetTester tester) async { final Key key0 = UniqueKey(); final Key key1 = UniqueKey(); final Key key2 = UniqueKey(); // This list of children appears in a Row and an OverflowBar, so each // find.byKey() for key0, key1, key2 returns two widgets. final List<Widget> children = <Widget>[ SizedBox(key: key0, width: 50, height: 50), SizedBox(key: key1, width: 70, height: 50), SizedBox(key: key2, width: 80, height: 50), ]; const List<MainAxisAlignment> allAlignments = <MainAxisAlignment>[ MainAxisAlignment.start, MainAxisAlignment.center, MainAxisAlignment.end, MainAxisAlignment.spaceBetween, MainAxisAlignment.spaceAround, MainAxisAlignment.spaceEvenly, ]; const List<TextDirection> allTextDirections = <TextDirection>[ TextDirection.ltr, TextDirection.rtl, ]; Widget buildFrame(MainAxisAlignment alignment, TextDirection textDirection) { return Directionality( textDirection: textDirection, child: Column( children: <Widget>[ OverflowBar( alignment: alignment, children: children, ), Row( mainAxisAlignment: alignment, children: children, ), ], ), ); } // Each key from key0, key1, key2 maps to one child in the OverflowBar // and a matching child in the Row. We expect the children to be the // same size and for their left and right edges to align. void testLayout() { expect(tester.getSize(find.byType(OverflowBar)), const Size(800, 50)); for (final Key key in <Key>[key0, key1, key2]) { final Finder matchingChildren = find.byKey(key); expect(matchingChildren.evaluate().length, 2); final Rect rect0 = tester.getRect(matchingChildren.first); final Rect rect1 = tester.getRect(matchingChildren.last); expect(rect0.size, rect1.size); expect(rect0.left, rect1.left); expect(rect0.right, rect1.right); } } for (final MainAxisAlignment alignment in allAlignments) { for (final TextDirection textDirection in allTextDirections) { await tester.pumpWidget(buildFrame(alignment, textDirection)); testLayout(); } } }); }