import 'package:flutter_test/flutter_test.dart'; import 'package:miler/Models/stop_status.dart'; import 'package:miler/data/api_config.dart'; import 'package:miler/data/milk_run.dart'; import 'package:miler/data/service_profile.dart'; import 'package:miler/views/Dashboard/home/trip.dart'; /// ───────────────────────────────────────────────────────────────────────── /// PICKED IS A RUNG, NOT A MOMENT /// /// The regression: tapping **Picked** put the stop straight onto the /// delivery-active rung, so the state the rider had just created was never /// shown to him. /// /// The cause was a true fact read as the wrong one. `pickup-complete` releases /// hyperlocal work itself — pickup and delivery pincodes sharing a 3-digit /// prefix means the parcel never sees a hub — so the consignment is stamped /// `Out_for_Delivery` in the same call that records the collection. Every /// DailyGrubs order is hyperlocal, so the very next poll after a successful /// Picked reported `Out_for_Delivery`, and the ladder read that as "the rider /// is riding his round". /// /// It is not. It says the consignment *may be delivered*. Whether the rider has /// set off is something only the app knows, and it knows it at the moment he /// opens the stop. /// /// These tests hold the two apart. Nothing here asserts on a fabricated status: /// the backend value under test is the one the contract says `pickup-complete` /// writes. /// ───────────────────────────────────────────────────────────────────────── void main() { setUp(() => ServiceProfile.setActive(ServiceProfile.milkMan)); tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel)); /// A stop as the queue hands it over, with `orderstatus` already translated /// out of the booking enum the way `pickupFromBooking` does it. Map stop(String backendStatus) => { 'orderid': '1001', 'pickupid': 1001, 'sourcename': 'Vidhya Kitchen', 'orderstatus': ApiConfig.legacyStatusFromNew(backendStatus), 'pickuplat': 11.01, 'pickuplon': 76.95, 'droplat': 11.05, 'droplon': 76.99, }; group('the rung after a successful Picked', () { test('a released consignment the rider has not started is PICKED', () { // The exact state one poll after the slide: booking converted, // consignment already out for delivery, rider still at the counter. expect( MilkRun.stageOf( stop('Out_for_Delivery'), acceptedIds: {'1001'}, collectedIds: {'1001'}, outForDeliveryIds: const {}, ), StopStatus.picked, reason: 'Out_for_Delivery is the consignment being releasable, not the ' 'rider having set off', ); }); test('Converted_To_Consignment is PICKED too', () { // The non-hyperlocal half of the same call. Both endings of // `pickup-complete` have to land on the same rung, or the word on the // card would depend on the customer's pincode. expect( MilkRun.stageOf( stop('Converted_To_Consignment'), acceptedIds: {'1001'}, collectedIds: {'1001'}, ), StopStatus.picked, ); }); test('ACTIVE needs the rider to have opened the stop', () { expect( MilkRun.stageOf( stop('Out_for_Delivery'), acceptedIds: {'1001'}, collectedIds: {'1001'}, outForDeliveryIds: {'1001'}, ), StopStatus.outForDelivery, ); }); test('the whole ladder still runs in order', () { // Pending → Picked → Active → Delivered, end to end, with the backend // saying `Out_for_Delivery` from the second rung onward — which is what // it really does. final s = stop('Pickup_Scheduled'); expect( MilkRun.stageOf(s, acceptedIds: {'1001'}, collectedIds: const {}), StopStatus.accepted, ); final picked = stop('Out_for_Delivery'); expect( MilkRun.stageOf(picked, acceptedIds: {'1001'}, collectedIds: {'1001'}), StopStatus.picked, ); expect( MilkRun.stageOf( picked, acceptedIds: {'1001'}, collectedIds: {'1001'}, outForDeliveryIds: {'1001'}, ), StopStatus.outForDelivery, ); expect( MilkRun.stageOf( picked, acceptedIds: {'1001'}, collectedIds: {'1001'}, outForDeliveryIds: {'1001'}, deliveredIds: {'1001'}, ), StopStatus.delivered, ); }); }); group('states the backend genuinely owns still win', () { test('a delivered stop is never dragged back to picked', () { expect( MilkRun.stageOf( stop('Delivered'), acceptedIds: {'1001'}, collectedIds: {'1001'}, outForDeliveryIds: const {}, ), StopStatus.delivered, ); }); test('an arrival at the door outranks the release', () { final s = stop('Out_for_Delivery')..['orderstatus'] = 'deliveryarrived'; expect( MilkRun.stageOf(s, acceptedIds: {'1001'}, collectedIds: {'1001'}), StopStatus.deliveryArrived, ); }); }); group('after a reload', () { test('a released consignment is carried work, never live work', () { // The collected set lives in prefs and a reinstall empties it. Before, // `outfordelivery` matched nothing in `stopStateOf` and the row fell // through to `pending` — putting a bag already in the rider's box back on // Home as work to accept. final state = stopStateOf( stop('Out_for_Delivery'), acceptedIds: const {}, rejectedIds: const {}, collectedIds: const {}, ); expect(state, StopState.collected); expect(state, isNot(StopState.active)); expect(state, isNot(StopState.pending)); }); test('a started round survives, because the marker is on the device', () { // The rider opened the stop before the app was killed. `startPickup` // wrote the id, prefs kept it, and the rung comes back ACTIVE — which is // the one case where the UI may say so. expect( MilkRun.stageOf( stop('Out_for_Delivery'), acceptedIds: const {}, collectedIds: const {}, outForDeliveryIds: {'1001'}, ), StopStatus.outForDelivery, ); }); }); }