import "package:flutter/widgets.dart"; import "package:flutter_test/flutter_test.dart"; import "package:garage_ui/garage_ui.dart"; import "support/test_scheme.dart"; // the rows sat flush against each other and the surface took the same radius // they do, so the corner gap didnt match the gap down the sides. const _density = Density(); Widget _host() => Directionality( textDirection: TextDirection.ltr, child: GarageTheme( data: ThemeData(colorScheme: testScheme, density: _density), child: Align( alignment: Alignment.topLeft, child: SizedBox( width: 600, height: 400, child: Overlay( initialEntries: [ OverlayEntry( builder: (_) => Align( alignment: Alignment.topLeft, child: SizedBox( width: 160, child: Select( value: "normal", itemBuilder: (ctx, v) => const Text("Normal"), onChanged: (_) {}, popup: const SelectPopup( items: SelectItemList( children: [ SelectItemButton( value: "normal", child: Text("Normal"), ), SelectItemButton( value: "comfortable", child: Text("Comfortable"), ), ], ), ), ), ), ), ), ], ), ), ), ), ); Rect _rowOf(WidgetTester tester, String label) => tester.getRect( find.ancestor( of: find.text(label), matching: find.byType(SelectItemButton), ), ); void main() { testWidgets("theres air between one row and the next", (tester) async { await tester.pumpWidget(_host()); await tester.tap(find.byType(Select)); await tester.pumpAndSettle(); final first = _rowOf(tester, "Normal"); final second = _rowOf(tester, "Comfortable"); final gap = second.top - first.bottom; expect(gap, greaterThan(0), reason: "rows were flush"); expect(gap, closeTo(_density.gapXxs, 0.5)); }); testWidgets("the surface rounds around the rows, less a couple of px", ( tester, ) async { await tester.pumpWidget(_host()); await tester.tap(find.byType(Select)); await tester.pumpAndSettle(); final theme = ThemeData(colorScheme: testScheme, density: _density); final inset = theme.density.containerGap * 0.5; final border = theme.density.controlBorderWidth; // the surface is the one decorated box wrapping the rows final surface = tester.widgetList(find.byType(Container)).where(( c, ) { final d = c.decoration; return d is BoxDecoration && d.borderRadius != null && d.border != null; }); expect(surface, isNotEmpty); final radii = surface .map((c) => ((c.decoration as BoxDecoration).borderRadius as BorderRadius).topLeft.x) .toList(); final expected = theme.radiusMd + inset + border - 2; expect( radii.any((r) => (r - expected).abs() < 0.01), isTrue, reason: "wanted a surface at $expected, saw $radii", ); }); testWidgets("it hangs off the trigger by gapSm, not the container gap", ( tester, ) async { await tester.pumpWidget(_host()); final trigger = tester.getRect(find.byType(Select)); await tester.tap(find.byType(Select)); await tester.pumpAndSettle(); final scroller = tester.getRect(find.byType(SingleChildScrollView).first); // the scroller starts just inside the surface's border, so back that off // to get the surface's own top edge final border = _density.controlBorderWidth; final toSurface = scroller.top - border - trigger.bottom; expect(toSurface, closeTo(_density.gapSm, 0.5)); expect(toSurface, lessThan(_density.containerGap)); }); testWidgets("the rows still sit inside the padding", (tester) async { await tester.pumpWidget(_host()); await tester.tap(find.byType(Select)); await tester.pumpAndSettle(); final row = _rowOf(tester, "Normal"); final theme = ThemeData(colorScheme: testScheme, density: _density); final inset = theme.density.containerGap * 0.5; // the scroller holds the padding, so the row starts one inset inside it final scroller = tester.getRect(find.byType(SingleChildScrollView).first); expect(row.left - scroller.left, closeTo(inset, 0.5)); expect(row.top - scroller.top, closeTo(inset, 0.5)); }); }