production
This commit is contained in:
220
test/arrived_rung_test.dart
Normal file
220
test/arrived_rung_test.dart
Normal file
@@ -0,0 +1,220 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'package:miler/Models/stop_status.dart';
|
||||
import 'package:miler/data/accepted_store.dart';
|
||||
import 'package:miler/data/api_config.dart';
|
||||
import 'package:miler/data/consignment_state.dart';
|
||||
import 'package:miler/data/milk_run.dart';
|
||||
import 'package:miler/data/service_profile.dart';
|
||||
|
||||
/// ─────────────────────────────────────────────────────────────────────────
|
||||
/// TWO RUNGS THAT WERE NOT THERE
|
||||
///
|
||||
/// Reported from a milk run, and they are the same failure at two ends of the
|
||||
/// ladder: a rung the rider walked was not a rung the app kept.
|
||||
///
|
||||
/// 1. **Arrived did nothing.** He marked arrived at the kitchen, the row went
|
||||
/// back to ACCEPTED, and the sheet offered him arrival again. The write
|
||||
/// was fine. `POST /miler/bookings/:id/reached` answers 200 and leaves the
|
||||
/// booking on `Miler_Assigned` (request 15), so the rung lived only as a
|
||||
/// field on an in-memory row — and `_advanceStopWithSheet` finishes with
|
||||
/// `_fetchQueues()`, which rebuilt that row from the server about a second
|
||||
/// later. Nothing kept his report, so nothing showed it.
|
||||
///
|
||||
/// 2. **Picked jumped to active.** He slid to collect and the card went
|
||||
/// straight to ACTIVE without ever showing PICKED, with **Start delivery**
|
||||
/// never offered. `pickup-complete` in compatibility mode releases the
|
||||
/// consignment itself, so the stop reached the Deliveries tab already
|
||||
/// `Out_for_Delivery` — and the release gate read that as "he has set
|
||||
/// off".
|
||||
///
|
||||
/// The ladder the rider actually walks, and what answers each rung:
|
||||
///
|
||||
/// ```
|
||||
/// ACCEPTED the queue, or the accepted store
|
||||
/// ARRIVED HIS report → the arrived store (nothing else has it)
|
||||
/// PICKED pickup-complete → the collected store
|
||||
/// ACTIVE HIS press → the out-for-delivery store
|
||||
/// DELIVERED deliver
|
||||
/// ```
|
||||
///
|
||||
/// Two of the five are the rider's own and cannot be read back from anywhere.
|
||||
/// That is why they are stored, and it is the whole content of both bugs.
|
||||
/// ─────────────────────────────────────────────────────────────────────────
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
setUp(() {
|
||||
SharedPreferences.setMockInitialValues({});
|
||||
ServiceProfile.setActive(ServiceProfile.milkMan);
|
||||
});
|
||||
tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel));
|
||||
|
||||
/// A stop as the queue hands it over.
|
||||
Map<String, dynamic> stop(String backendStatus, {String id = '1001'}) => {
|
||||
'orderid': id,
|
||||
'pickupid': int.parse(id),
|
||||
'sourcename': 'Vidhya Kitchen',
|
||||
'orderstatus': ApiConfig.legacyStatusFromNew(backendStatus),
|
||||
'pickuplat': 11.01,
|
||||
'pickuplon': 76.95,
|
||||
'droplat': 11.05,
|
||||
'droplon': 76.99,
|
||||
};
|
||||
|
||||
group('1 · arrival is kept, because nothing else keeps it', () {
|
||||
test('the server does not persist it — this is the premise', () {
|
||||
// Not an assertion about our code: it is the reason the store exists.
|
||||
// `reached` leaves the booking where it was, so a poll cannot return the
|
||||
// rung and the app cannot read it back.
|
||||
expect(
|
||||
ApiConfig.legacyStatusFromNew('Miler_Assigned'),
|
||||
isNot('arrived'),
|
||||
reason:
|
||||
'if this ever becomes "arrived" the backend has shipped request '
|
||||
'15 and the arrived store should be deleted, not kept',
|
||||
);
|
||||
});
|
||||
|
||||
test('an arrival survives being written and read back', () async {
|
||||
await addArrivedOrderIds(['1001']);
|
||||
expect(await getArrivedOrderIds(), {'1001'});
|
||||
});
|
||||
|
||||
test(
|
||||
'the rung it produces is ARRIVED, over a queue that says accepted',
|
||||
() async {
|
||||
await addArrivedOrderIds(['1001']);
|
||||
final arrived = await getArrivedOrderIds();
|
||||
|
||||
// What `_fetchQueues` does with the set: the row comes back on
|
||||
// Miler_Assigned and the rider's own record puts it back on the rung.
|
||||
final row = stop('Miler_Assigned');
|
||||
expect(
|
||||
stopStatusFromRaw(row['orderstatus']),
|
||||
isNot(StopStatus.arrived),
|
||||
reason: 'the server really does hand it back one rung down',
|
||||
);
|
||||
|
||||
if (arrived.contains(row['orderid'])) row['orderstatus'] = 'arrived';
|
||||
|
||||
expect(
|
||||
MilkRun.stageOf(
|
||||
row,
|
||||
acceptedIds: {'1001'},
|
||||
collectedIds: const {},
|
||||
outForDeliveryIds: const {},
|
||||
),
|
||||
StopStatus.arrived,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test('and it is dropped the moment the stop is collected', () async {
|
||||
await addArrivedOrderIds(['1001']);
|
||||
await removeArrivedOrderIds(['1001']);
|
||||
expect(
|
||||
await getArrivedOrderIds(),
|
||||
isEmpty,
|
||||
reason:
|
||||
'a local record that outlives its rung pins tomorrow\'s row to '
|
||||
'yesterday\'s arrival',
|
||||
);
|
||||
});
|
||||
|
||||
test('one kitchen\'s arrival does not move another\'s stop', () async {
|
||||
await addArrivedOrderIds(['1001']);
|
||||
expect(await getArrivedOrderIds(), isNot(contains('2002')));
|
||||
});
|
||||
});
|
||||
|
||||
group('2 · picked is not active until he says so', () {
|
||||
test('compatibility mode really does release at the counter', () {
|
||||
// The premise of the second bug, stated as the contract does: a
|
||||
// hyperlocal booking is `Out_for_Delivery` the moment it is collected.
|
||||
expect(consignmentStateFromRaw('Out_for_Delivery').isDeliverable, isTrue);
|
||||
expect(
|
||||
consignmentStateFromRaw('Out_for_Delivery').needsRelease,
|
||||
isFalse,
|
||||
reason:
|
||||
'which is exactly why reading needsRelease first skipped the rung '
|
||||
'— the consignment does not need releasing, the RIDER has not '
|
||||
'released it',
|
||||
);
|
||||
});
|
||||
|
||||
test('the card holds at PICKED while the round is unstarted', () {
|
||||
expect(
|
||||
MilkRun.stageOf(
|
||||
stop('Out_for_Delivery'),
|
||||
acceptedIds: {'1001'},
|
||||
collectedIds: {'1001'},
|
||||
outForDeliveryIds: const {},
|
||||
),
|
||||
StopStatus.picked,
|
||||
);
|
||||
});
|
||||
|
||||
test('and moves to ACTIVE only on his own press', () {
|
||||
expect(
|
||||
MilkRun.stageOf(
|
||||
stop('Out_for_Delivery'),
|
||||
acceptedIds: {'1001'},
|
||||
collectedIds: {'1001'},
|
||||
outForDeliveryIds: {'1001'},
|
||||
),
|
||||
StopStatus.outForDelivery,
|
||||
);
|
||||
});
|
||||
|
||||
test('a delivered stop is never dragged back down the ladder', () {
|
||||
// The one direction the local sets must not win in: the server knows
|
||||
// something the rider's phone does not.
|
||||
expect(
|
||||
MilkRun.stageOf(
|
||||
stop('Delivered'),
|
||||
acceptedIds: {'1001'},
|
||||
collectedIds: {'1001'},
|
||||
outForDeliveryIds: const {},
|
||||
),
|
||||
StopStatus.delivered,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('3 · the ladder in order, walked once', () {
|
||||
test('accepted → arrived → picked → active', () async {
|
||||
final row = stop('Miler_Assigned');
|
||||
final collected = <String>{};
|
||||
final released = <String>{};
|
||||
|
||||
StopStatus rung() => MilkRun.stageOf(
|
||||
row,
|
||||
acceptedIds: {'1001'},
|
||||
collectedIds: collected,
|
||||
outForDeliveryIds: released,
|
||||
);
|
||||
|
||||
expect(rung(), StopStatus.accepted);
|
||||
|
||||
// He arrives.
|
||||
await addArrivedOrderIds(['1001']);
|
||||
row['orderstatus'] = 'arrived';
|
||||
expect(rung(), StopStatus.arrived);
|
||||
|
||||
// He collects. pickup-complete converts and — in compatibility mode —
|
||||
// releases; the rider's rung is still PICKED.
|
||||
await removeArrivedOrderIds(['1001']);
|
||||
row['orderstatus'] = 'picked';
|
||||
row['consignmentstatus'] = 'Out_for_Delivery';
|
||||
collected.add('1001');
|
||||
expect(rung(), StopStatus.picked);
|
||||
expect(await getArrivedOrderIds(), isEmpty);
|
||||
|
||||
// He slides to start the ride.
|
||||
released.add('1001');
|
||||
expect(rung(), StopStatus.outForDelivery);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user