import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:get/get.dart'; import 'package:miler/data/service_profile.dart'; import 'package:miler/views/Dashboard/home/route_timeline.dart'; import 'package:miler/views/Dashboard/home/trip.dart'; import 'package:miler/views/Dashboard/home/trip_card.dart'; /// ───────────────────────────────────────────────────────────────────────── /// `Accepted 1/10`, NOT `Accepted 1/63` /// /// The kitchen card's state chip is a fraction: how many of this counter's /// orders the rider has taken, out of how many there are. The numerator was /// right and the denominator was the whole day. /// /// ── What it was counting ── /// /// [RouteGroup.allStops] is every order the trip ever bucketed under a source, /// and `groupSize` was its raw length. That deliberately includes orders the /// rider has **collected** — they left the visible list but not the counter, /// and renumbering the place under him is how a rider stops trusting a number. /// /// It also included every order already **delivered** and every one he had /// **declined**, which are Activity's business and not this card's. Off a /// kitchen that supplies a rider all day that is most of the bucket: ten orders /// in the dropdown, one accepted, and a chip reading `Accepted 1/63` — a /// fraction whose denominator appears nowhere on the screen. /// /// The load is now stated the way the rider would state it: **what is still in /// the dropdown, plus what he has already taken off this counter**. /// ───────────────────────────────────────────────────────────────────────── void main() { tearDown(() { Get.reset(); ServiceProfile.setActive(ServiceProfile.parcel); }); /// One order off Vidhya Kitchen. [status] is what the backend calls it, which /// is what `stopStateOf` reads to place it on the ladder. Map order(int id, {required String status}) => { 'orderid': 'M-$id', 'pickupid': id, 'step': id, 'kitchenname': 'Vidhya Kitchen', 'sourceid': 'K1', 'pickupcustomer': 'Customer $id', 'pickupaddress': '9 Kitchen Street, Coimbatore', 'dropaddress': 'Door $id, Peelamedu, Coimbatore', 'orderstatus': status, 'type': 'delivery', 'pickuplat': 11.01, 'pickuplon': 76.95, }; /// The card's own grouping, run the way the screen runs it. List groupsFor( List> stops, { Set accepted = const {}, Set collected = const {}, }) { ServiceProfile.setActive(ServiceProfile.milkMan); return TripCard( trip: Trip.fromStops(id: 'T1', stops: stops), acceptedIds: accepted, collectedIds: collected, ).routeGroups(); } group('the denominator is the counter, not the day', () { test('ten in the dropdown and one accepted reads 1 of 10', () { // The reported case, at the size it was reported: one kitchen, ten // orders still to decide, and fifty-three already delivered today. final stops = >[ for (var i = 1; i <= 10; i++) order(i, status: 'assigned'), for (var i = 11; i <= 63; i++) order(i, status: 'delivered'), ]; final g = groupsFor(stops, accepted: {'M-1'}).single; expect(g.stops.length, 10, reason: 'the dropdown holds ten'); expect(g.allStops.length, 63, reason: 'the bucket still holds the day'); expect(g.onRungCount, 1); expect( g.groupSize, 10, reason: 'fifty-three delivered orders are Activity\'s, not this card\'s', ); }); test('a collected order keeps its place in the arithmetic', () { // The original rationale, which must survive the fix: three bags are in // the rider's box and off Home, but they came off this counter and the // place still holds six. final stops = >[ for (var i = 1; i <= 6; i++) order(i, status: 'assigned'), ]; final g = groupsFor( stops, accepted: {'M-1', 'M-2', 'M-3'}, collected: {'M-1', 'M-2', 'M-3'}, ).single; expect(g.stops.length, 3, reason: 'the collected three left Home'); expect( g.groupSize, 6, reason: 'renumbering the counter under him is the bug this prevents', ); }); test('a declined order drops out of the load', () { final stops = >[ for (var i = 1; i <= 4; i++) order(i, status: 'assigned'), order(5, status: 'rejected'), ]; final g = groupsFor(stops).single; expect(g.groupSize, 4, reason: 'he has finished with the declined one'); }); test('nothing delivered means the two counts agree', () { final stops = >[ for (var i = 1; i <= 5; i++) order(i, status: 'assigned'), ]; final g = groupsFor(stops).single; expect(g.groupSize, 5); expect(g.groupSize, g.allStops.length); }); test('a caller that tracks no states gets the old arithmetic', () { // Better to over-count than to invent a denominator: a hand-built group // with no `allStopStates` must not silently report zero. const g = RouteGroup( key: 'K1', name: 'Vidhya Kitchen', stops: [], allStops: [{}, {}, {}], firstIndex: 0, state: StopState.pending, stopStates: [], ); expect(g.groupSize, 3); }); }); group('the chip on the card says the same number', () { Future pump( WidgetTester tester, List> stops, { Set accepted = const {}, }) async { ServiceProfile.setActive(ServiceProfile.milkMan); tester.view.physicalSize = const Size(390 * 3, 1600 * 3); tester.view.devicePixelRatio = 3; addTearDown(tester.view.reset); await tester.pumpWidget( ScreenUtilInit( designSize: const Size(390, 844), builder: (_, _) => MaterialApp( home: Scaffold( body: SingleChildScrollView( child: TripCard( trip: Trip.fromStops(id: 'T1', stops: stops), acceptedIds: accepted, onToggleSelect: (_) {}, ), ), ), ), ), ); await tester.pumpAndSettle(); } testWidgets('the accepted chip is a fraction of the dropdown', ( tester, ) async { await pump(tester, [ for (var i = 1; i <= 10; i++) order(i, status: 'assigned'), for (var i = 11; i <= 63; i++) order(i, status: 'delivered'), ], accepted: {'M-1'}); expect(find.text('Accepted 1/10'), findsOneWidget); expect( find.text('Accepted 1/63'), findsNothing, reason: 'the day is not the counter', ); }); testWidgets('a single-order place states no fraction at all', ( tester, ) async { // `Accepted (1 of 1)` is noise, and the guard for it reads `groupSize`. await pump( tester, [order(1, status: 'assigned')], accepted: {'M-1'}, ); expect(find.text('Accepted'), findsOneWidget); expect(find.textContaining('Accepted 1/'), findsNothing); }); }); }