import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:miler/data/service_profile.dart'; import 'package:miler/data/stop_area.dart'; import 'package:miler/views/Dashboard/home/homepage_banner.dart'; import 'package:miler/views/Dashboard/pickups/pickups.dart'; import 'package:miler/views/helpers/constants/Colorconstants.dart'; /// ───────────────────────────────────────────────────────────────────────── /// THE WORK QUEUE, NOT A LIST OF CARDS /// /// Deliveries answers one question — *where do I go now, and what do I do /// there* — and the whole screen is ranked around it: NOW is the command /// object, UP NEXT is a glance, LATER recedes. That ranking has to be legible /// **before** the labels are read, or the labels are the only thing carrying /// it. /// /// These pin the invariants that ranking depends on, plus the two geometry /// rules the bottom of this screen has broken twice. /// ───────────────────────────────────────────────────────────────────────── void main() { _realAddresses(); tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel)); Map drop(String id, String who, {String? address}) => { 'orderid': id, 'type': 'delivery', 'orderstatus': 'outfordelivery', 'pickupcustomer': who, 'sourcename': 'DailyGrubs RS Puram Kitchen', 'kitchenname': 'DailyGrubs RS Puram Kitchen', 'pickupaddress': '9 Mettupalayam Road, RS Puram, Coimbatore 641002', 'dropaddress': address ?? '12, SNS Colony, Peelamedu, Coimbatore 641004', 'pickupcontactno': '9787698259', }; group('the collapsed queue names a place, not a street', () { test('an area, never a truncated address', () { // The screen's own anti-pattern, named in the brief: twenty rows of // `SEQTEST Gandhipur…` answer nothing a blank line would not have. final area = areaOf(drop('1', 'Joe Mathew')); expect(area, isNot(contains('641004'))); expect(area, isNot(contains('12,'))); expect(area.length, lessThan(24)); expect(RegExp(r'[0-9]').hasMatch(area), isFalse); }); test('a delivery names where the bag is GOING', () { ServiceProfile.setActive(ServiceProfile.milkMan); // Once he is carrying it, the kitchen is supporting information. The // destination is the question. // `Peelamedu`, not `SNS Colony` — the locality, not the sub-locality. // See the live-data group above for why the rule prefers a one-word name. expect(areaOf(drop('1', 'Joe Mathew'), preferDrop: true), 'Peelamedu'); expect( areaOf(drop('1', 'Joe Mathew'), preferDrop: false), 'Mettupalayam Road'.contains('9') ? isNotEmpty : 'RS Puram', ); }); test('a stop with nothing usable yields nothing, never a placeholder', () { expect(areaOf(const {'orderid': '1'}), ''); }); test('one implementation, shared with Home', () { // Two copies of this rule got the same subtle case wrong in the same // way: `12 SNS Colony` returned as an area because it is not *entirely* // digits. One function is one place to find that. expect( areaOf({'dropaddress': '4/2 Cross Cut Road, Gandhipuram, 641012'}), 'Gandhipuram', ); }); }); group('the bottom slot is one slot', () { /// `maxHeight` is expressed in `.h`, like every dimension in this app, so /// these run inside a pumped `ScreenUtilInit` rather than as pure tests. Future ready(WidgetTester tester) async { tester.view.physicalSize = const Size(390 * 3, 844 * 3); tester.view.devicePixelRatio = 3.0; addTearDown(tester.view.reset); await tester.pumpWidget( ScreenUtilInit( designSize: const Size(390, 844), builder: (_, _) => const MaterialApp(home: SizedBox.shrink()), ), ); } testWidgets('the reservation follows whichever surface is showing', ( tester, ) async { await ready(tester); const inset = 34.0; // Live stop: the banner is up, and the floor clears the banner. expect( bottomReservationFor(inset: inset, live: true, unreleased: true), inset + ActivePickupBanner.maxHeight, ); // A live stop suppresses the start bar, so the banner wins even when // there is unreleased work — the two never stack. expect( bottomReservationFor(inset: inset, live: true, unreleased: false), inset + ActivePickupBanner.maxHeight, ); // Nothing running, load in hand: the start bar. expect( bottomReservationFor(inset: inset, live: false, unreleased: true), inset + StartRoundBar.maxHeight, ); }); testWidgets('the device inset is always counted', (tester) async { await ready(tester); // The regression: the live branch was a flat `80.h` that forgot the // inset, so on a gesture-navigation phone the last row of the run sat // behind the banner *and* behind the navigation. for (final live in const [true, false]) { final withInset = bottomReservationFor( inset: 34, live: live, unreleased: true, ); final without = bottomReservationFor( inset: 0, live: live, unreleased: true, ); expect(withInset - without, 34); } }); testWidgets('an idle queue reserves almost nothing', (tester) async { await ready(tester); expect( bottomReservationFor(inset: 0, live: false, unreleased: false), lessThan(StartRoundBar.maxHeight), ); }); testWidgets('both surfaces declare a real height', (tester) async { await ready(tester); // Measured, not guessed. Each is the only thing that knows how much of // the list it covers. expect(ActivePickupBanner.maxHeight, greaterThan(48)); expect(StartRoundBar.maxHeight, greaterThan(48)); }); }); group('the command surface', () { Future pumpBar( WidgetTester tester, { double width = 390, double textScale = 1.0, int count = 5, }) async { ServiceProfile.setActive(ServiceProfile.milkMan); tester.view.physicalSize = Size(width * 3, 844 * 3); tester.view.devicePixelRatio = 3.0; addTearDown(tester.view.reset); 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( backgroundColor: ColorConstants.daylightSurface, body: Align( alignment: Alignment.bottomCenter, child: StartRoundBar( count: count, busy: false, onPressed: () {}, ), ), ), ), ), ); await tester.pumpAndSettle(); } testWidgets('it says what is in hand and what the press does', ( tester, ) async { await pumpBar(tester); // Setting off is reversible and operational, so it is a press — unlike // Picked and Delivered, which are assertions about custody. expect(find.textContaining('Start'), findsOneWidget); }); for (final (width, scale) in const [ (390.0, 1.0), (390.0, 1.3), (390.0, 2.0), (375.0, 2.0), (320.0, 1.0), (320.0, 2.0), ]) { testWidgets('${width.toInt()}px @ ${scale}x lays out clean', ( tester, ) async { await pumpBar(tester, width: width, textScale: scale, count: 12); expect(tester.takeException(), isNull); }); } testWidgets('it never wraps itself in a second SafeArea', (tester) async { await pumpBar(tester); // `BottomPage.bottomInset` is the one owner of the device inset on this // screen. A `SafeArea` here would count it twice and float the bar a // navigation bar's height off the bottom of the screen. expect( find.descendant( of: find.byType(StartRoundBar), matching: find.byType(SafeArea), ), findsNothing, ); }); }); } /// Real addresses from the live tenant, added after seeing them render on a /// device. The rule that only skipped digits printed the landmark — /// `Coimbatore Gandhipuram Mofussil Bus Stand` — on every row of the run. void _realAddresses() { group('the area rule against live data', () { const cases = { 'Coimbatore Gandhipuram Mofussil Bus Stand, Sathyamurthi Road, ' 'Gandhipuram, Ward 54, Central Zone, Coimbatore, ' 'Coimbatore North, Coimbatore, Tamil Nadu, 641001, India': 'Gandhipuram', '12, SNS Colony, Peelamedu, Coimbatore 641004': 'Peelamedu', '4 Cross, RS Puram, Coimbatore 641002': 'RS Puram', '19, Thadagam Road, Venkitapuram, Coimbatore': 'Venkitapuram', }; cases.forEach((address, expected) { test('"${address.split(',').first}…" → $expected', () { expect(areaOf({'dropaddress': address}), expected); }); }); test('a landmark never wins over the locality behind it', () { final area = areaOf(const { 'dropaddress': 'Coimbatore Gandhipuram Mofussil Bus Stand, ' 'Sathyamurthi Road, Gandhipuram, Coimbatore', }); expect(area.split(' ').length, 1, reason: 'an area is a name'); expect(area, isNot(contains('Bus Stand'))); }); }); }