test(studio): lock sidebar destination Y-stability on rail expansion
Adds a widget test asserting each destination icon keeps its Y position whether the rail is collapsed or expanded — a recurring regression. To drive expansion without a hover gesture (which trips RenderFlex overflow mid-transition), a test-only startSidebarExpanded flag threads StudioApp -> StudioShell -> _Sidebar (controller starts at 1.0, hover disabled); _SidebarItems get stable ValueKeys. analyze clean; new test and the existing smoke test pass. Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
parent
d66f46f133
commit
36a8252f67
2 changed files with 103 additions and 5 deletions
77
test/sidebar_test.dart
Normal file
77
test/sidebar_test.dart
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// Locks the sidebar invariant: destination icons sit at the same Y
|
||||
// whether the rail is collapsed or expanded. The header rows above the
|
||||
// destinations list have FIXED pixel heights (see _SidebarState), so
|
||||
// expanding the rail (a width-only change) must not shift any
|
||||
// destination vertically. This was a recurring regression source; this
|
||||
// test pins it.
|
||||
//
|
||||
// Expansion is driven via StudioApp(startSidebarExpanded: true), NOT a
|
||||
// hover gesture — hover mid-transition trips RenderFlex overflow in
|
||||
// widget tests (see widget_test.dart). With the flag the rail's
|
||||
// animation controller starts at value 1.0 (fully expanded), so no
|
||||
// animation needs to settle.
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:chain_studio/data/hub.dart';
|
||||
import 'package:chain_studio/main.dart';
|
||||
|
||||
const _destinations = <String>[
|
||||
'welcome',
|
||||
'store',
|
||||
'doctor',
|
||||
'flows',
|
||||
'audit',
|
||||
'approvals',
|
||||
'federation',
|
||||
];
|
||||
|
||||
Map<String, double> _destinationYs(WidgetTester tester) {
|
||||
final ys = <String, double>{};
|
||||
for (final id in _destinations) {
|
||||
final finder = find.byKey(ValueKey('sidebar-item-$id'));
|
||||
expect(finder, findsOneWidget, reason: 'destination "$id" must render');
|
||||
ys[id] = tester.getTopLeft(finder).dy;
|
||||
}
|
||||
return ys;
|
||||
}
|
||||
|
||||
void main() {
|
||||
testWidgets(
|
||||
'sidebar destination Y positions are stable across rail expansion',
|
||||
(tester) async {
|
||||
// Collapsed (default).
|
||||
await tester.pumpWidget(
|
||||
const StudioApp(
|
||||
initialThemeMode: ThemeModeValue.system,
|
||||
initialLocale: Locale('en'),
|
||||
),
|
||||
);
|
||||
// pump (not pumpAndSettle): the app has long-lived timers/animations
|
||||
// that never "settle"; one frame is enough to lay the sidebar out.
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
final collapsed = _destinationYs(tester);
|
||||
|
||||
// Expanded: controller starts at 1.0 via the flag, hover disabled.
|
||||
await tester.pumpWidget(
|
||||
const StudioApp(
|
||||
initialThemeMode: ThemeModeValue.system,
|
||||
initialLocale: Locale('en'),
|
||||
startSidebarExpanded: true,
|
||||
),
|
||||
);
|
||||
await tester.pump(const Duration(milliseconds: 100));
|
||||
final expanded = _destinationYs(tester);
|
||||
|
||||
for (final id in _destinations) {
|
||||
expect(
|
||||
expanded[id],
|
||||
closeTo(collapsed[id]!, 0.5),
|
||||
reason: 'destination "$id" Y shifted on expansion '
|
||||
'(${collapsed[id]} -> ${expanded[id]}) — the rows above the '
|
||||
'destinations list must keep fixed heights',
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue