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

150 lines
5.3 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:miler/views/Dashboard/home/trip.dart';
import 'package:miler/data/service_profile.dart';
/// ─────────────────────────────────────────────────────────────────────────
/// THE BRIEF DESCRIBES WHAT IS LEFT
///
/// Home's brief card carries four figures — duration, distance, parcels,
/// payment — under a headline that counts down (`20 stops left`).
///
/// The headline moved as the rider worked. The figures did not. They were
/// counted once over every stop the slot ever held, so a rider with five
/// collections to go read `≈4h 15m · 29.0 km · 25 parcels`: the morning he
/// started with, including the twenty already in his box and gone to
/// Deliveries. The one question the card exists to answer — *what is in front
/// of me* — was the one thing on it that was stale.
///
/// [Trip.outstanding] is the recount. The line it draws is
/// `WorkBoundary.pickupComplete`, the same boundary Home and Deliveries split
/// on, so a stop cannot be counted here and owned there.
/// ─────────────────────────────────────────────────────────────────────────
void main() {
tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel));
Map<String, dynamic> stop(
String id, {
String status = 'accepted',
int parcels = 1,
double lat = 11.0,
double lng = 76.95,
double cash = 0,
}) => {
'orderid': id,
'pickupid': id,
'orderstatus': status,
'pickupquantity': parcels,
'pickuplat': lat,
'pickuplon': lng,
'collectionamt': cash,
};
group('what the figures count', () {
test('a collected stop drops out of every figure', () {
final trip = Trip.fromStops(
id: 't1',
stops: [
stop('A', status: 'picked', lat: 11.00, lng: 76.90),
stop('B', lat: 11.05, lng: 76.95),
stop('C', lat: 11.10, lng: 77.00),
],
hubLat: 11.0,
hubLng: 76.95,
);
final left = trip.outstanding(originLat: 11.0, originLng: 76.95);
expect(trip.stopCount, 3, reason: 'the trip itself is untouched');
expect(left.stopCount, 2);
expect(left.totalParcels, lessThan(trip.totalParcels));
expect(left.totalDuration, lessThan(trip.totalDuration));
expect(left.routeMeters, lessThan(trip.routeMeters));
});
test('the local collected record counts, not just the status', () {
// The queue is a poll behind, so a stop the rider has just handed over
// still reports its old status. `collectedIds` is what closes that
// window — the same set Home writes after pickup-complete returns.
final trip = Trip.fromStops(
id: 't1',
stops: [stop('A'), stop('B')],
);
expect(trip.outstanding().stopCount, 2, reason: 'nothing collected yet');
expect(trip.outstanding(collectedIds: const {'A'}).stopCount, 1);
});
test('nothing collected returns the very same object', () {
// The common case — a rider who has not started — must not pay for a
// rebuild of the whole trip on every frame of the brief.
final trip = Trip.fromStops(id: 't1', stops: [stop('A'), stop('B')]);
expect(identical(trip.outstanding(), trip), isTrue);
});
test('skipped and cancelled work is not still-to-do', () {
final trip = Trip.fromStops(
id: 't1',
stops: [
stop('A', status: 'skipped'),
stop('B', status: 'cancelled'),
stop('C'),
],
);
expect(
trip.outstanding().stopCount,
1,
reason: 'a written-off stop is a record, not a stop to plan around',
);
});
test('a run with everything collected leaves nothing to describe', () {
final trip = Trip.fromStops(
id: 't1',
stops: [
stop('A', status: 'picked'),
stop('B', status: 'picked'),
],
);
final left = trip.outstanding();
expect(left.stopCount, 0);
expect(left.totalParcels, 0);
expect(
left.totalDuration,
Duration.zero,
reason: 'the four cells fall back to the em dash, not to a stale figure',
);
});
});
group('payment on a meal run', () {
test('is nothing to collect, whatever the payload says', () {
ServiceProfile.setActive(ServiceProfile.milkMan);
final trip = Trip.fromStops(
id: 't1',
stops: [stop('A', cash: 250), stop('B', cash: 130)],
);
// The cell prints the em dash when this is zero — the rider on a meal
// run is never asked for money, so a figure here would be a prompt to
// collect one.
expect(trip.outstanding().cashToCollect, 0);
});
test('but a parcel route still counts the cash it is owed', () {
ServiceProfile.setActive(ServiceProfile.parcel);
final trip = Trip.fromStops(
id: 't1',
stops: [
stop('A', status: 'picked', cash: 250),
stop('B', cash: 130),
],
);
expect(
trip.outstanding().cashToCollect,
130,
reason: 'the collected stop\'s cash is no longer waiting to be taken',
);
});
});
}