Files
Garage-SDKs/garage_ui/test/field_feature_height_test.dart
T
ImBenjiandClaude Opus 5.5 b269201919 The Garage SDKs, in the open
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
2026-09-23 18:49:21 +01:00

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",
);
}
}
});
}
}