import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:miler/views/Dashboard/home/trip.dart'; import 'package:miler/views/Dashboard/home/trip_tabs.dart'; /// ───────────────────────────────────────────────────────────────────────── /// THE SELECTOR STAYS PUT, AND IT STAYS ONE HEIGHT /// /// This file used to guard a pinned `SliverPersistentHeader`: the delegate had /// to declare a fixed extent, [TripSelector]'s content was type that grows with /// the system font, and the two disagreed by a few pixels at large settings — /// so `extentFor` derived an over-estimate and these tests measured it from /// 1.0× to 2.0× to prove it was never short. /// /// **None of that exists any more.** The selector moved into the brand header, /// which is fixed by being the Column's first child rather than by being a /// sliver, so there is no extent to declare and nothing to under-estimate. /// /// What survives is the property the arithmetic was protecting, and it is now /// the widget's own: the control is a **fixed height** that does not move with /// the text scale. A header that grows a few points at 1.5× pushes the whole /// page down and re-lays the route out under the rider's thumb. It cannot, /// because nothing in the control is free-flowing type — the numeral is inside /// a `FittedBox` that scales it down into the space it has. /// ───────────────────────────────────────────────────────────────────────── void main() { Map stop(String id) => { 'orderid': id, 'pickupid': id, 'pickupcustomer': 'Sri Balaji Stores', 'pickupaddress': '19, Thadagam Road, Coimbatore', 'orderstatus': 'pending', }; Future pump( WidgetTester tester, { required int trips, int selected = 0, double textScale = 1.0, }) async { tester.view.physicalSize = const Size(390 * 3, 844 * 3); tester.view.devicePixelRatio = 3.0; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); await tester.pumpWidget( ScreenUtilInit( designSize: const Size(390, 844), builder: (_, _) => MaterialApp( builder: (context, child) => MediaQuery( data: MediaQuery.of( context, ).copyWith(textScaler: TextScaler.linear(textScale)), child: child!, ), home: Scaffold( body: Padding( padding: const EdgeInsets.all(16), child: TripSelector( trips: [ for (var i = 0; i < trips; i++) Trip.fromStops(id: 't$i', stops: [stop('$i')]), ], selectedIndex: selected, onSelect: (_) {}, ), ), ), ), ), ); await tester.pump(); } group('the control is one height at every text scale', () { for (final scale in const [1.0, 1.3, 1.5, 2.0]) { testWidgets('at ${scale}x', (tester) async { await pump(tester, trips: 2, textScale: scale); await tester.pump(const Duration(milliseconds: 400)); expect( tester.getSize(find.byType(TripSelector)).height, TripSelector.height, reason: 'the header must not change height with the font, or the whole ' 'route below it moves under the rider\'s thumb', ); expect(tester.takeException(), isNull); }); } }); testWidgets('three slots render before the hub has filled them', ( tester, ) async { await pump(tester, trips: 1); for (final n in ['Trip 1', 'Trip 2', 'Trip 3']) { expect(find.text(n), findsOneWidget); } }); testWidgets('exactly one segment is marked, and it is the selected one', ( tester, ) async { await pump(tester, trips: 2, selected: 1); await tester.pump(const Duration(milliseconds: 400)); final marks = find.byKey(TripSelector.markerKey); expect(marks, findsOneWidget, reason: 'one trip is current, not two'); // The rule is a short centred mark under its pill rather than a full-width // underline, so what has to hold is that it is centred on the *right* // pill — not that it spans it. final marker = tester.getRect(marks); final second = tester.getRect(find.text('Trip 2')); expect( marker.center.dx, closeTo(second.center.dx, 6), reason: 'the rule sits under the pill it belongs to', ); expect( marker.top, greaterThan(second.bottom), reason: 'and under it, not through it', ); }); testWidgets('the indicator is a rule, not a filled tab', (tester) async { // The tabs sit straight on the brand ground: no card, no wash, no outline. // Selection is the travelling rule and the ink weight, and nothing else. await pump(tester, trips: 2); await tester.pump(const Duration(milliseconds: 400)); final marker = tester.getSize(find.byKey(TripSelector.markerKey)); expect( marker.height, lessThanOrEqualTo(4), reason: 'a 2-3dp rule, not a segment-sized fill', ); }); testWidgets('a segment is tappable and reports its own index', ( tester, ) async { int? chosen; tester.view.physicalSize = const Size(390 * 3, 844 * 3); tester.view.devicePixelRatio = 3.0; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); await tester.pumpWidget( ScreenUtilInit( designSize: const Size(390, 844), builder: (_, _) => MaterialApp( home: Scaffold( body: Padding( padding: const EdgeInsets.all(16), child: TripSelector( trips: [ Trip.fromStops(id: 't0', stops: [stop('0')]), Trip.fromStops(id: 't1', stops: [stop('1')]), ], selectedIndex: 0, onSelect: (i) => chosen = i, ), ), ), ), ), ); await tester.pump(); await tester.tap(find.text('Trip 2')); expect(chosen, 1); }); }