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/views/Dashboard/home/trip.dart'; import 'package:miler/views/Dashboard/pickups/stop_type.dart'; import 'package:miler/views/helpers/constants/Colorconstants.dart'; import 'package:miler/views/Dashboard/home/trip_card.dart'; import 'package:miler/views/helpers/widgets/app_widgets.dart'; /// P2 — what a stop card says on a service tenant. /// /// The three facts under test are the three a rider reads before he moves: what /// kind of work this is, where the order has got to, and which bag out of ten in /// his box belongs at this door. void main() { tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel)); group('the work-type chip', () { test('Doormile still names each stop kind separately', () { ServiceProfile.setActive(ServiceProfile.parcel); expect(StopKind.pickup.chipLabel, 'PICKUP'); expect(StopKind.delivery.chipLabel, 'DELIVERY'); expect(StopKind.combined.chipLabel, 'P&D'); expect(StopKind.pickup.chipColor, ColorConstants.pickupChip); }); test('a milk run wears one mark, and it is not the line’s name', () { // ── This assertion changed with product direction ── // // It used to require the word MILK. That is the app's internal name for // a *service profile* — the thing that decides which capabilities exist // and whose records belong to whom — and it was being printed on the // rider's cards and on his Activity record as `Type: MILK`. He did not // choose it, cannot change it and gains nothing from reading it. // // What has NOT changed is the property the mark exists for: on this line // every stop wears the *same* mark, because the rider handles a kitchen // crate and a subscriber's doorstep identically and a chip that flipped // between them would imply a difference in handling that does not exist. ServiceProfile.setActive(ServiceProfile.meals); for (final kind in StopKind.values) { expect(kind.chipLabel, 'DELIVERY', reason: '$kind'); expect(kind.badgeLabel, 'DELIVERY', reason: '$kind'); expect(kind.chipColor, ColorConstants.serviceChip, reason: '$kind'); } // Sentence case where the type is stated as a label rather than stamped. expect(StopKind.delivery.titleLabel, 'Delivery'); // And the internal name reaches no screen at all. for (final kind in StopKind.values) { expect(kind.chipLabel.toUpperCase(), isNot(contains('MILK'))); expect(kind.titleLabel.toUpperCase(), isNot(contains('MILK'))); } }); test('the stop keeps its real kind underneath the one label', () { ServiceProfile.setActive(ServiceProfile.meals); // P3's collection gate depends on this still being true: a kitchen stop // is a pickup and a subscriber drop is a delivery, whatever the chip says. expect(stopKindOf({'type': 'delivery'}), StopKind.delivery); expect(stopKindOf({'type': 'pickup'}), StopKind.pickup); }); }); group('the status tag', () { test('a parcel route names a pending stop as a decision it awaits', () { ServiceProfile.setActive(ServiceProfile.parcel); expect(StopState.pending.label, 'Awaiting your decision'); expect(StopState.done.label, 'Completed'); }); test('a meal rider is told the state, not asked for a decision', () { ServiceProfile.setActive(ServiceProfile.meals); // He accepted the whole assignment at once — there is no per-stop // decision left to await. expect(StopState.pending.label, 'Pending'); expect(StopState.active.label, 'Out for delivery'); expect(StopState.done.label, 'Delivered'); expect(StopState.skipped.label, 'Skipped'); }); }); group('source and bag label', () { test('read the spellings the backend might send', () { expect(stopSourceName({'kitchenname': 'Kitchen 1'}), 'Kitchen 1'); expect(stopSourceName({'SourceName': ' Anna Nagar '}), 'Anna Nagar'); expect(stopSourceId({'kitchenid': 'K-77'}), 'K-77'); expect(stopBagLabel({'baglabel': 'DG-1042'}), 'DG-1042'); expect(stopBagLabel({'labelcode': 'DG-9'}), 'DG-9'); }); test( 'absent on a parcel stop rather than empty-stringed onto the card', () { expect(stopSourceName({'orderid': '7'}), ''); expect(stopBagLabel({'orderid': '7'}), ''); }, ); }); group('StopSourceLine', () { Future pump(WidgetTester tester, String source, String bag) async { await tester.pumpWidget( ScreenUtilInit( designSize: const Size(390, 844), builder: (_, _) => MaterialApp( home: Scaffold( body: StopSourceLine(source: source, bagLabel: bag), ), ), ), ); await tester.pumpAndSettle(); } testWidgets('takes no space at all on a stop with neither', (tester) async { await pump(tester, '', ''); // A Doormile card must be exactly what it was — not what it was plus an // empty row's padding. final size = tester.getSize(find.byType(StopSourceLine)); expect(size.height, 0); }); testWidgets('shows both when the stop carries both', (tester) async { await pump(tester, 'Kitchen 1', 'DG-1042'); expect(find.text('Kitchen 1'), findsOneWidget); expect(find.text('Bag DG-1042'), findsOneWidget); }); testWidgets('shows the bag alone when there is no source', (tester) async { await pump(tester, '', 'DG-1042'); expect(find.text('Bag DG-1042'), findsOneWidget); expect( tester.getSize(find.byType(StopSourceLine)).height, greaterThan(0), ); }); }); group('the stop row on a service tenant', () { /// [withSource] mirrors the payload difference between the two tenants: a /// parcel booking has no kitchen and no bag label to send, which is why a /// Doormile card is unchanged by P2 — the line is driven by the data, not /// by who the rider works for. Map stop({bool withSource = true}) => { 'orderid': '1', 'step': 1, 'customername': 'Priya Sundaram', 'pickupaddress': '2B Lakshmi Flats, 4th Main Road, Anna Nagar East', 'status': 'ASSIGNED', 'type': 'delivery', 'quantity': 1, if (withSource) 'kitchenname': 'Kitchen 1', if (withSource) 'baglabel': 'DG-1042', 'pickuplat': 13.08, 'pickuplon': 80.21, }; Future pumpRoute( WidgetTester tester, { bool withSource = true, }) async { tester.view.physicalSize = const Size(1080, 1800); tester.view.devicePixelRatio = 3.0; addTearDown(tester.view.resetPhysicalSize); addTearDown(tester.view.resetDevicePixelRatio); final trip = Trip.fromStops( id: 't1', stops: [stop(withSource: withSource)], ); await tester.pumpWidget( ScreenUtilInit( designSize: const Size(390, 844), builder: (_, _) => MaterialApp( home: Scaffold( body: SingleChildScrollView( child: TripCard(trip: trip).buildStops(), ), ), ), ), ); await tester.pumpAndSettle(); } // ── The row's marks moved up to the place ── // // A card carried a work-type chip and a state chip of its own, and the // truncation test above was about the two of them sharing one line. Neither // is on a timeline row: the type is progressive disclosure in the detail // sheet, and the *state* belongs to the place rather than to each order // under it — five orders off one counter are all on the same rung, so five // copies of the same chip said nothing five times. // // What survives is the half that was always the contract: the kitchen is // named once, and the bag the order travels in is on the row. testWidgets('the kitchen is named once and the bag rides on the row', ( tester, ) async { ServiceProfile.setActive(ServiceProfile.meals); await pumpRoute(tester); // Named once, by the place — not again on every order under it. expect(find.text('Kitchen 1'), findsOneWidget); // The label the kitchen printed, straight from [BagManifest]. The `Bag ` // prefix belonged to the card's chip and went with it, which stopped a // printed `DG-1042` reading as `Bag DG-1042`. expect(find.text('DG-1042'), findsOneWidget); // The count the rider checks the shelf against. expect(find.text('1 bag'), findsOneWidget); }); testWidgets('a parcel route keeps a bare pending row', (tester) async { ServiceProfile.setActive(ServiceProfile.parcel); await pumpRoute(tester, withSource: false); // The row underneath carries the decision, so a chip would be a caption // on a control. expect(find.text('Awaiting your decision'), findsNothing); // And nothing from the meal run leaks onto a parcel route: no counter to // group under, so the stop is its own node and no bag arithmetic applies. expect(find.text('Kitchen 1'), findsNothing); expect(find.text('MILK'), findsNothing); expect(find.text('1 order · 1 bag'), findsNothing); expect(find.text('Priya Sundaram'), findsOneWidget); }); }); }