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
This commit is contained in:
ImBenji
2026-09-23 18:49:21 +01:00
co-authored by Claude Opus 5.5
commit b269201919
117 changed files with 26944 additions and 0 deletions
+154
View File
@@ -0,0 +1,154 @@
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, density: const Density()),
child: Align(
alignment: Alignment.topLeft,
child: SizedBox(width: 400, child: child),
),
),
);
void main() {
testWidgets("rules go between entries, not around them", (tester) async {
await tester.pumpWidget(
_host(
SettingsList(
children: [
SettingsRow(label: "Full name", field: const Text("Benjamin")),
SettingsRow(label: "Nickname", field: const Text("Benji")),
SettingsRow(label: "Work", field: const Text("Engineering")),
],
),
),
);
// three rows, two rules - a rule above the first or below the last would
// draw the box this exists to not be
expect(find.byType(Divider), findsNWidgets(2));
});
testWidgets("the rule runs wider than the rows it separates", (
tester,
) async {
await tester.pumpWidget(
_host(
SettingsList(
children: [
SettingsRow(label: "Read", field: const Text("Optional")),
SettingsRow(label: "Change", field: const Text("Optional")),
],
),
),
);
final rule = tester.getRect(find.byType(Divider));
final row = tester.getRect(find.byType(SettingsRow).first);
// overshoots at both ends - a rule that stops where its content stops
// reads as the edge of a box rather than a divider
expect(rule.left, lessThan(row.left));
expect(rule.right, greaterThan(row.right));
});
testWidgets("one entry has no rule at all", (tester) async {
await tester.pumpWidget(
_host(
SettingsList(
children: [
SettingsRow(label: "Full name", field: const Text("Benjamin")),
],
),
),
);
expect(find.byType(Divider), findsNothing);
});
testWidgets("label takes the room the field doesnt", (tester) async {
await tester.pumpWidget(
_host(
SettingsList(
children: [
SettingsRow(
label: "What best describes your work?",
field: const SizedBox(width: 120, height: 20),
),
],
),
),
);
final label = tester.getRect(find.text("What best describes your work?"));
final field = tester.getRect(find.byType(SizedBox).last);
final row = tester.getRect(find.byType(SettingsRow));
// label on the left, field hard against the right edge - not floating in
// the middle at the left of its own share of the row
expect(label.left, lessThan(field.left));
expect(field.width, 120);
expect(field.right, closeTo(row.right, 1));
expect(tester.takeException(), isNull);
});
testWidgets("a field with flex children inside it doesnt assert", (
tester,
) async {
// the field slot is bounded, not unbounded - a ButtonGroup with `fill`,
// or anything else holding an Expanded, needs a width to divide up.
await tester.pumpWidget(
_host(
SettingsList(
children: [
SettingsRow(
label: "Read",
field: ButtonGroup.horizontal(
fill: true,
children: [
Button(
style: const ButtonStyle.outline(),
onPressed: () {},
child: const Text("Off"),
),
Button(
style: const ButtonStyle.outline(),
onPressed: () {},
child: const Text("Required"),
),
],
),
),
],
),
),
);
expect(tester.takeException(), isNull);
});
testWidgets("a long label doesnt push the field off the row", (
tester,
) async {
await tester.pumpWidget(
_host(
SettingsList(
children: [
SettingsRow(
label: "See your account, passkeys and sign-in activity, and "
"everything else besides",
field: const SizedBox(width: 120, height: 20),
),
],
),
),
);
expect(tester.takeException(), isNull);
expect(tester.getSize(find.byType(SizedBox).last).width, 120);
});
}