Files
Garage-SDKs/garage_ui/test/nested_button_group_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

150 lines
4.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 group inside a group. The inner one used to install its own scope over the
// outer one's, so the outer's say was simply lost: the bottom row's field kept
// the top corners the vertical group had flattened, and painted a top edge the
// row above had already drawn.
//
// Corners are 0-or-1 keep factors, so composing is a product - a corner stays
// round only where BOTH groups leave it alone.
void main() {
ButtonGroupCorners cornersOf(WidgetTester tester, Type type) {
final ctx = tester.element(find.byType(type));
return ButtonGroupScope.maybeOf(ctx)!.corners;
}
ButtonGroupScope scopeOf(WidgetTester tester, Key key) {
return ButtonGroupScope.maybeOf(tester.element(find.byKey(key)))!;
}
testWidgets("a horizontal group nested in a vertical one composes", (
tester,
) async {
const top = Key("top");
const bottomStart = Key("bottom-start");
const bottomEnd = Key("bottom-end");
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: GarageTheme(
data: ThemeData(colorScheme: testScheme, density: const Density()),
child: Center(
child: SizedBox(
width: 300,
child: ButtonGroup.vertical(
expands: true,
children: [
const SizedBox(key: top, height: 20),
// no expands on the inner group - it keeps the
// IntrinsicHeight that bounds it inside the vertical one.
ButtonGroup.horizontal(
children: const [
Expanded(child: SizedBox(key: bottomStart, height: 20)),
SizedBox(key: bottomEnd, height: 20, width: 20),
],
),
],
),
),
),
),
),
);
// top row: vertical index 0 - both top corners live, bottom flattened
// against the row below.
final t = scopeOf(tester, top);
expect(
[t.corners.topStart, t.corners.topEnd],
[1, 1],
reason: "the top row keeps its top corners",
);
expect(
[t.corners.bottomStart, t.corners.bottomEnd],
[0, 0],
reason: "the top row's bottom is a seam",
);
expect(t.hideTop, isFalse);
expect(t.hideStart, isFalse);
// bottom-left: bottom of the vertical group AND start of the horizontal
// one, so the ONLY surviving corner is bottom-start.
final bs = scopeOf(tester, bottomStart);
expect(
[
bs.corners.topStart,
bs.corners.topEnd,
bs.corners.bottomStart,
bs.corners.bottomEnd,
],
[0, 0, 1, 0],
reason: "only the outer bottom-start corner survives both groups",
);
expect(
bs.hideTop,
isTrue,
reason: "the row above already painted this edge",
);
expect(bs.hideStart, isFalse, reason: "its the first in its own row");
// bottom-right: bottom of the vertical AND end of the horizontal, so only
// bottom-end survives - and it gives up BOTH its top and its start edge,
// which is the pair a single axis+index could never express.
final be = scopeOf(tester, bottomEnd);
expect(
[
be.corners.topStart,
be.corners.topEnd,
be.corners.bottomStart,
be.corners.bottomEnd,
],
[0, 0, 0, 1],
);
expect(be.hideTop, isTrue, reason: "the row above painted the top edge");
expect(
be.hideStart,
isTrue,
reason: "the field beside it painted the start edge",
);
});
testWidgets("an unnested group is unchanged", (tester) async {
const a = Key("a");
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: GarageTheme(
data: ThemeData(colorScheme: testScheme, density: const Density()),
child: Center(
child: ButtonGroup.horizontal(
children: const [
SizedBox(key: a, height: 20, width: 20),
SizedBox(height: 20, width: 20),
],
),
),
),
),
);
final s = scopeOf(tester, a);
expect(
[
s.corners.topStart,
s.corners.topEnd,
s.corners.bottomStart,
s.corners.bottomEnd,
],
[1, 0, 1, 0],
);
expect(s.hideTop, isFalse);
expect(s.hideStart, isFalse);
});
}