import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:miler/data/api_config.dart'; import 'package:miler/data/service_profile.dart'; import 'package:miler/views/Dashboard/pickups/pickups.dart'; /// ───────────────────────────────────────────────────────────────────────── /// A HANDOVER CARD NAMES THE BASE IT IS SENDING HIM TO /// /// The card already refused to lead with the receiver, and was right to — on a /// base leg he is in another district, and heading the card with him is the /// navigation mistake that rule exists to prevent. /// /// But refusing the receiver only left the *pickup*, so a handover card read: /// /// BASE HANDOVER /// Anitha R /// Gandhipuram /// /// …the customer he had collected from an hour earlier, under a heading telling /// him to go to a base. The place he was actually going appeared nowhere on the /// card — only on the sheet's slider, after he had already set off. On a round /// with two bases that is a parcel left in the wrong building. /// /// `next_hub` rides on the row (the backend sends all six fields: id, name, /// address, pincode, latitude, longitude), so the destination is knowable at /// card-build time and there is no excuse for the card not to say it. /// ───────────────────────────────────────────────────────────────────────── void main() { setUp(() => ServiceProfile.setActive(ServiceProfile.parcel)); tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel)); Future pump(WidgetTester tester, Widget child) async { tester.view.physicalSize = const Size(1170, 2532); 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: SingleChildScrollView(child: child)), ), ), ); await tester.pumpAndSettle(); } /// A collected parcel routed to a base — the row as the queue returns it with /// `MILER_HUB_HANDOVER_ENABLED` on. Map hubStop({Map? hub}) => ApiConfig.pickupFromBooking({ 'bookingid': 4821, 'orderid': 'ORDER-HUB-1', 'status': 'Converted_To_Consignment', 'consignmentstatus': 'Created', 'consignmentid': 77, 'next_action': 'inward_at_hub', 'sourcename': 'Anitha R', 'pickupcustomer': 'Anitha R', 'pickupaddress': '12 Gandhipuram, Coimbatore', 'recipientname': 'Ravi Kumar', 'dropaddress': '88 Anna Nagar, Chennai 600040', 'next_hub': hub ?? const { 'id': 1, 'name': 'Coimbatore Base', 'address': '14 Avinashi Road, Peelamedu', 'pincode': '641004', 'latitude': 11.0272, 'longitude': 76.9905, }, }); /// The same parcel, going to a customer instead. Map customerStop() => ApiConfig.pickupFromBooking(const { 'bookingid': 4822, 'orderid': 'ORDER-CX-1', 'consignmentstatus': 'Out_for_Delivery', 'consignmentid': 78, 'next_action': 'deliver', 'pickupcustomer': 'Anitha R', 'pickupaddress': '12 Gandhipuram, Coimbatore', 'recipientname': 'Ravi Kumar', 'dropaddress': '4 Race Course, Coimbatore 641018', }); testWidgets('the BASE leads, not the sender he collected from', ( tester, ) async { await pump( tester, PickupCard( item: hubStop(), displayStep: 1, distanceMeters: 4200, collectedIds: const {'ORDER-HUB-1'}, ), ); expect(find.text('BASE HANDOVER'), findsOneWidget); expect( find.text('Coimbatore Base'), findsOneWidget, reason: 'the rider must know WHICH base without opening a sheet', ); expect( find.text('Anitha R'), findsNothing, reason: 'the sender he collected from an hour ago is not the destination', ); }); testWidgets('the base address is readable at a gate', (tester) async { await pump( tester, PickupCard( item: hubStop(), displayStep: 1, distanceMeters: 4200, collectedIds: const {'ORDER-HUB-1'}, ), ); // Street and pincode, not the locality summary the other legs use — // "Peelamedu" alone does not find a loading bay. expect( find.textContaining('14 Avinashi Road'), findsOneWidget, ); expect(find.textContaining('641004'), findsOneWidget); }); testWidgets('the distant receiver never takes the headline', (tester) async { await pump( tester, PickupCard( item: hubStop(), displayStep: 1, distanceMeters: 4200, collectedIds: const {'ORDER-HUB-1'}, ), ); // The rule that predates this change and must survive it: a Chennai // receiver on a parcel going to a Coimbatore base must not be drawn as the // place the rider is heading. expect(find.text('Ravi Kumar'), findsNothing); }); testWidgets('a base with no coordinates still names itself', (tester) async { // It is a caption rather than a destination — navigating to 0,0 lands in // the Gulf of Guinea — but the rider still needs to read which base it is. // The geofence refuses the handover separately, with a sentence pointing at // the office. await pump( tester, PickupCard( item: hubStop(hub: const {'id': 2, 'name': 'Salem Base'}), displayStep: 1, distanceMeters: 4200, collectedIds: const {'ORDER-HUB-1'}, ), ); expect(find.text('BASE HANDOVER'), findsOneWidget); // Once — the name is the headline, and the address line stays empty rather // than repeating it. expect(find.text('Salem Base'), findsOneWidget); }); testWidgets('a customer delivery still leads with the RECIPIENT', ( tester, ) async { // The other half of the contract. This change must not push the base // treatment onto a leg that has a real receiver — that fix (recipient, not // sender) was itself a production bug once. await pump( tester, PickupCard( item: customerStop(), displayStep: 1, distanceMeters: 1400, collectedIds: const {'ORDER-CX-1'}, ), ); expect(find.text('CUSTOMER DELIVERY'), findsOneWidget); expect(find.text('Ravi Kumar'), findsOneWidget); // The sender IS still on the card, and should be: once the parcel is in the // box the pickup is history, but it is what establishes custody and on a // run with two counters it is how he knows which shelf the label came off. // It sits under a hairline at half the weight — so "leads" is a claim about // TYPE SIZE, and that is what gets asserted rather than mere presence. expect(find.text('Anitha R'), findsOneWidget); double sizeOf(String text) => tester.widget(find.text(text)).style?.fontSize ?? 0; expect( sizeOf('Ravi Kumar'), greaterThan(sizeOf('Anitha R')), reason: 'the receiver leads; the sender is context beneath him', ); }); testWidgets('on a base leg the sender is not drawn as context either', ( tester, ) async { // The context block is gated on `dropLeads`, which is false for a base leg // — so a handover card carries the base and nothing that could be mistaken // for a destination. await pump( tester, PickupCard( item: hubStop(), displayStep: 1, distanceMeters: 4200, collectedIds: const {'ORDER-HUB-1'}, ), ); expect(find.text('Anitha R'), findsNothing); expect(find.text('Ravi Kumar'), findsNothing); expect(find.text('Coimbatore Base'), findsOneWidget); }); }