garage_auth, garage_entitlements, garage_iap and garage_ui, moved out of Garage-Services and Metro-Map-Maker into one public repo. MIT, one readme, docs under docs/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013F4NWNvYcdeSgqbWMT1VQ7
113 lines
3.5 KiB
Dart
113 lines
3.5 KiB
Dart
import "package:flutter/widgets.dart";
|
|
import "package:flutter_test/flutter_test.dart";
|
|
import "package:garage_ui/garage_ui.dart";
|
|
|
|
import "support/test_scheme.dart";
|
|
|
|
// A feature lives INSIDE the field. It never gets to decide how tall the field
|
|
// is - that is the density's job and nothing elses.
|
|
//
|
|
// It used to. The field wrapped its whole content row in textFieldPadding, so
|
|
// anything you put in a feature slot got the padding stacked on top of its own
|
|
// height. A trailing IconButton is a full control tall (23 at compact), so the
|
|
// field came out at 23 + 12 = 35 against a controlHeight of 23 - half again as
|
|
// tall as the plain field sat next to it. The packages OWN InputFeature.clear()
|
|
// did it too, which is how it survived this long unnoticed.
|
|
//
|
|
// The existing feature-height probe in the app only ever passed a bare Text, so
|
|
// none of this was covered.
|
|
|
|
Future<double> _height(
|
|
WidgetTester tester, {
|
|
required Density density,
|
|
required List<InputFeature> features,
|
|
String text = "",
|
|
}) async {
|
|
final controller = TextEditingController(text: text);
|
|
await tester.pumpWidget(
|
|
Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: GarageTheme(
|
|
data: ThemeData(colorScheme: testScheme, density: density),
|
|
child: Center(
|
|
child: SizedBox(
|
|
width: 300,
|
|
child: TextField(controller: controller, features: features),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pump();
|
|
return tester.getSize(find.byType(TextField)).height;
|
|
}
|
|
|
|
void main() {
|
|
for (final density in const [Density(), Density.normal()]) {
|
|
final label = density.control.name;
|
|
|
|
testWidgets("a trailing button doesnt grow the field ($label)", (
|
|
tester,
|
|
) async {
|
|
final plain = await _height(tester, density: density, features: const []);
|
|
final withButton = await _height(
|
|
tester,
|
|
density: density,
|
|
features: [
|
|
InputFeature.trailing(
|
|
IconButton(
|
|
variance: ButtonVariance.ghost,
|
|
density: ControlDensity.compact,
|
|
icon: const Icon(LucideIcons.eye),
|
|
onPressed: () {},
|
|
),
|
|
),
|
|
],
|
|
);
|
|
|
|
expect(plain, density.controlHeight);
|
|
expect(
|
|
withButton,
|
|
plain,
|
|
reason:
|
|
"a button in a trailing slot pushed the field to $withButton "
|
|
"against a plain $plain",
|
|
);
|
|
});
|
|
|
|
testWidgets("every built-in feature holds controlHeight ($label)", (
|
|
tester,
|
|
) async {
|
|
final cases = <String, List<InputFeature>>{
|
|
"leading icon": const [InputFeature.leading(Icon(LucideIcons.lock))],
|
|
"clear": [const InputFeature.clear()],
|
|
"spinner": [const InputFeature.spinner()],
|
|
"increment": [const InputFeature.incrementButton()],
|
|
"scrub": [const InputFeature.scrub()],
|
|
};
|
|
|
|
for (final entry in cases.entries) {
|
|
// empty AND filled - the clear button only shows up once theres text.
|
|
for (final text in const ["", "12"]) {
|
|
final h = await _height(
|
|
tester,
|
|
density: density,
|
|
features: entry.value,
|
|
text: text,
|
|
);
|
|
expect(
|
|
tester.takeException(),
|
|
isNull,
|
|
reason: "${entry.key} threw laying out in the field",
|
|
);
|
|
expect(
|
|
h,
|
|
density.controlHeight,
|
|
reason: "${entry.key} made the field $h",
|
|
);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|