import "package:flutter/widgets.dart"; import "package:flutter_test/flutter_test.dart"; import "package:garage_ui/garage_ui.dart"; import "support/test_scheme.dart"; Widget _host(Widget child) => Directionality( textDirection: TextDirection.ltr, child: GarageTheme( data: ThemeData(colorScheme: testScheme), child: Center(child: SizedBox(width: 400, child: child)), ), ); Widget _row({String? error}) => _host( SettingsRow( key: const Key("row"), label: "Name", error: error, field: const TextField(), ), ); void main() { testWidgets("the label's aside renders beside it, not instead of it", ( tester, ) async { await tester.pumpWidget( _host( const SettingsRow( label: "Name", action: Text("Required"), field: TextField(), ), ), ); expect(find.text("Name"), findsOneWidget); expect(find.text("Required"), findsOneWidget); // on the label's line, and at the FAR right of its half of the row - // spaceBetween, the way ProductField does it in the onboarding flow. final label = tester.getRect(find.text("Name")); final tag = tester.getRect(find.text("Required")); final field = tester.getRect(find.byType(TextField)); expect((tag.center.dy - label.center.dy).abs(), lessThan(2)); // tucked against the label rather than pushed to the far end of the // column - one gap between them, not the whole remaining width. expect(tag.left - label.right, lessThan(12)); expect(tag.left, greaterThan(label.right - 1)); expect(tag.right, lessThan(field.left)); }); testWidgets("the aside reads as a tag, not as a second label", ( tester, ) async { await tester.pumpWidget( _host( const SettingsRow( label: "Name", action: Text("Required"), field: TextField(), ), ), ); final tag = tester.widget(find.text("Required")); final style = DefaultTextStyle.of( tester.element(find.text("Required")), ).style.merge(tag.style); final label = tester.widget(find.text("Name")); expect(style.fontSize, const Density().textXxs); expect(style.color, testScheme.mutedForeground); expect(style.fontSize, lessThan(label.style!.fontSize!)); }); testWidgets("a property row puts it in the same place", (tester) async { await tester.pumpWidget( _host( PropertyRow( label: "Price", scheme: testScheme, action: const Text("Required"), child: const TextField(), ), ), ); final label = tester.getRect(find.text("Price")); final tag = tester.getRect(find.text("Required")); final field = tester.getRect(find.byType(TextField)); expect(tag.left - label.right, lessThan(12)); expect(tag.right, lessThan(field.left)); }); testWidgets("the row eases open rather than jumping", (tester) async { await tester.pumpWidget(_row()); await tester.pumpAndSettle(); final bare = tester.getSize(find.byKey(const Key("row"))).height; await tester.pumpWidget(_row(error: "nope")); await tester.pump(); // the frame the change lands on final atStart = tester.getSize(find.byKey(const Key("row"))).height; await tester.pump(const Duration(milliseconds: 90)); final midway = tester.getSize(find.byKey(const Key("row"))).height; await tester.pumpAndSettle(); final settled = tester.getSize(find.byKey(const Key("row"))).height; expect(settled, greaterThan(bare)); expect(midway, greaterThan(atStart)); expect(midway, lessThan(settled)); }); testWidgets("the outline fades in", (tester) async { await tester.pumpWidget(_row()); await tester.pumpAndSettle(); await tester.pumpWidget(_row(error: "nope")); await tester.pump(); await tester.pump(const Duration(milliseconds: 90)); final fades = tester .widgetList(find.byType(FadeTransition)) .map((f) => f.opacity.value) .toList(); expect(fades.any((v) => v > 0.0 && v < 1.0), isTrue); }); }