Files
doormile_milderapp/test/arrived_stays_on_home_test.dart
2026-08-28 11:13:15 +05:30

162 lines
6.2 KiB
Dart

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/home/trip_card.dart';
/// ─────────────────────────────────────────────────────────────────────────
/// A STOP HE IS STANDING AT MUST NOT LEAVE THE SCREEN
///
/// Reported from a live run: the rider marked **Arrived**, the console updated
/// correctly — and the stop vanished off Home. Deliveries did not have it
/// either, and could not: arrival is a *pre-pickup* rung, and the delivery tab
/// only takes work once it is collected. The stop existed in neither place.
///
/// ── What caused it ──
///
/// Nothing on the backend. [StopState.arrived] and [StopState.active] used to
/// be one value, and `TripCard._showsOnHome` — like a dozen other sites — asked
/// `state == StopState.active` to mean *is he at the counter*. Splitting the
/// two apart so the row could say **Arrived** instead of **Active** left every
/// one of those comparisons answering `false` for the new rung.
///
/// The visibility filter was the one the rider could see. The others were just
/// as broken and quieter: the selection bar offered *Accept* for a stop he was
/// already at, the card stopped building its **Mark as picked** button, and the
/// group he was working no longer opened by default.
///
/// These pin the rung end to end — the predicate that now answers the question
/// once ([StopStateX.isAtSource]), and the screen behaviour that regressed.
/// ─────────────────────────────────────────────────────────────────────────
void main() {
tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel));
Map<String, dynamic> meal(String id, String who, {String? status}) => {
'orderid': id,
'type': 'delivery',
'step': int.parse(id),
'pickupcustomer': who,
'kitchenid': 'K1',
'kitchenname': 'Vidhya Kitchen',
'sourcename': 'Vidhya Kitchen',
'pickupcontactno': '9787698259',
'pickupaddress': '4 Cross, RS Puram, Coimbatore',
'dropaddress': '12 SNS Colony, Peelamedu, Coimbatore 641004',
'Quantity': '1',
if (status != null) 'orderstatus': status,
};
Future<void> pumpHome(
WidgetTester tester,
List<Map<String, dynamic>> stops,
) async {
ServiceProfile.setActive(ServiceProfile.milkMan);
tester.view.physicalSize = const Size(390 * 3, 2600 * 3);
tester.view.devicePixelRatio = 3.0;
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: 'run', stops: stops),
acceptedIds: const {},
selectedIds: const {},
onToggleSelect: (_) {},
onSelectAll: (_) {},
onStopTap: (_) {},
onCallStop: (_) {},
),
),
),
),
),
);
// Not `pumpAndSettle`: an arrived row is a **live** row, and [LiveMark]
// pulses for as long as it is on screen — settling waits for an animation
// that is never going to stop. Two pumps lay the frame out and let the
// pulse start, which is all these assertions need.
await tester.pump();
await tester.pump(const Duration(milliseconds: 300));
}
group('1 · the predicate that answers it once', () {
test('arrived and active both mean "he is at the source"', () {
expect(StopState.arrived.isAtSource, isTrue);
expect(StopState.active.isAtSource, isTrue);
});
test('and nothing else does', () {
for (final other in const [
StopState.pending,
StopState.accepted,
StopState.collected,
StopState.done,
StopState.skipped,
StopState.rejected,
]) {
expect(
other.isAtSource,
isFalse,
reason: '$other must not read as standing at the counter',
);
}
});
test('an arrived stop is committed work, not an open offer', () {
// It rode in on `active` and was dropped by the same split. A rider who
// has reported an arrival has plainly committed to the stop.
expect(StopState.arrived.isCommitted, isTrue);
expect(StopState.pending.isCommitted, isFalse);
});
});
group('2 · the screen behaviour that regressed', () {
testWidgets('an arrived stop stays on Home', (tester) async {
await pumpHome(tester, [
meal('1', 'Joe Mathew', status: 'arrived'),
meal('2', 'Arun Prakash'),
]);
expect(
find.text('Joe Mathew'),
findsOneWidget,
reason:
'the rider is standing at this counter — it cannot leave Home, '
'and Deliveries will not take it until it is collected',
);
});
testWidgets('it is still there beside an untouched stop', (tester) async {
// Guards the opposite overcorrection: making arrived visible must not
// have cost the ordinary rows their place in the run.
await pumpHome(tester, [
meal('1', 'Joe Mathew', status: 'arrived'),
meal('2', 'Arun Prakash'),
]);
expect(find.text('Joe Mathew'), findsOneWidget);
expect(find.text('Arun Prakash'), findsOneWidget);
});
testWidgets('a collected stop still leaves — that one is not a bug', (
tester,
) async {
// The filter's real job, asserted so a fix for the disappearance cannot
// quietly turn into "nothing ever leaves Home".
await pumpHome(tester, [
meal('1', 'Joe Mathew', status: 'picked'),
meal('2', 'Arun Prakash'),
]);
expect(find.text('Joe Mathew'), findsNothing);
expect(find.text('Arun Prakash'), findsOneWidget);
});
});
}