Files
doormile_milderapp/test/start_delivery_test.dart
Thiru-tenext d7348e253f Miler rider app: surface system, visible design language, backend lifecycle
Design system
- MilerSurface ladder (canvas → working → raised → floating) with MilerPanel
  as layer 1; canvas moved to #DEE3EA so white separates at 1.290:1.
- Visible vocabulary applied across Home, Deliveries, Activity, Account and
  the sheets: hero heads (tabular numeral + small caption, clamped at 1.3x),
  canvas wells for anything that opens, small filled tags for shelf labels,
  demoted placeholders. Recorded in DESIGN_SYSTEM.md §6.
- One icon family: 222 Material glyphs migrated to Lucide; none left outside
  lib/xpress.
- Colour semantics corrected: amber only for what is genuinely owed, brand red
  reserved for the live stop, disabled primaries go neutral rather than pale.

Data and lifecycle
- lib/data/lifecycle.dart reads mutations for what they prove; route_order.dart
  makes admin sequence the single ordering authority; service_day.dart, and
  stop_area.dart rewritten against live Coimbatore addresses (digit-token
  stripping, city stoplist, street suffixes, stammer collapse).
- countLabel states the load once, in bags.

Testing
- 1440 tests passing; golden shot harnesses for Home, Deliveries, Activity,
  sheets and verify, with test/failures/ now gitignored (diff debris).
- New pins: home_gutter_test, stop_area_test, plus updated structural bounds.

Note: this commit also carries pre-existing working-tree deletions that were
present before this work (API_SPEC.md, README.md, demo test fixtures).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 05:40:35 +05:30

138 lines
5.4 KiB
Dart

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/milk_run.dart';
import 'package:miler/data/service_profile.dart';
import 'package:miler/data/work_domain.dart';
/// ─────────────────────────────────────────────────────────────────────────
/// PICKED IS NOT OUT FOR DELIVERY
///
/// ── The regression ──
///
/// The release used to ride along with `pickup-complete`: the rider slid to
/// confirm five bags at a counter and the same gesture posted all five
/// consignments `Out_for_Delivery`. The hub's board then showed five **active**
/// deliveries for food still on the shelf in front of him, and the day had no
/// moment left in it meaning "I have set off" — picked and out-for-delivery had
/// been collapsed into one claim.
///
/// They are two claims about where the load is, made an hour apart, and only
/// the rider can make the second one. The ladder the hub sees is now:
///
/// ```
/// pickup-complete ──▶ Converted_To_Consignment admin: picked
/// START DELIVERY ──▶ Out_for_Delivery admin: active
/// deliver ──▶ Delivered admin: delivered
/// ```
///
/// These are the pure halves of that — the rung ladder and the stores it reads.
/// The press itself lives in `MyPickups.startRound`.
/// ─────────────────────────────────────────────────────────────────────────
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
setUp(() {
SharedPreferences.setMockInitialValues({});
ServiceProfile.setActive(ServiceProfile.milkMan);
});
tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel));
Map<String, dynamic> order(String id, {String status = 'picked'}) => {
'orderid': id,
'pickupid': int.parse(id),
'sourceid': 'K1',
'sourcename': 'Vidhya Kitchen',
'orderstatus': status,
'pickuplat': 11.01,
'pickuplon': 76.95,
'droplat': 11.05,
'droplon': 76.99,
};
group('after the counter, before the road', () {
test('a collected order is PICKED, not the delivery-active rung', () async {
await addCollectedOrderIds(['1001']);
expect(
MilkRun.stageOf(
order('1001'),
acceptedIds: {'1001'},
collectedIds: await getCollectedOrderIds(),
outForDeliveryIds: await getOutForDeliveryOrderIds(),
),
StopStatus.picked,
);
});
test('collecting does not release the round', () async {
// The whole regression in one line: nothing on the pickup path may write
// the released set. Only `startRound` does, and only after the server has
// agreed.
await addCollectedOrderIds(['1001', '1002']);
expect(await getOutForDeliveryOrderIds(), isEmpty);
});
test('an unreleased order is still on the deliveries tab', () async {
// The gate for the tab is the *collected* set, never the released one.
// Withholding uncollected-but-unreleased orders put them on no tab at
// all: dropped from Home as collected, hidden here as unstarted.
await addCollectedOrderIds(['1001']);
final queue = WorkBoundary.deliveryQueue(
[order('1001')],
collectedIds: await getCollectedOrderIds(),
acceptedIds: {'1001'},
);
expect(queue.map((s) => s['orderid']), ['1001']);
});
});
group('the press', () {
test('releasing the load moves it to the delivery-active rung', () async {
await addCollectedOrderIds(['1001', '1002']);
// What `startRound` writes once the server has accepted the batch.
await addOutForDeliveryOrderIds(['1001', '1002']);
for (final id in ['1001', '1002']) {
expect(
MilkRun.stageOf(
order(id),
acceptedIds: {id},
collectedIds: await getCollectedOrderIds(),
outForDeliveryIds: await getOutForDeliveryOrderIds(),
),
StopStatus.outForDelivery,
reason: '$id should be active once the round has started',
);
}
});
test('it survives a restart, because it is on the device', () async {
await addOutForDeliveryOrderIds(['1001']);
// A fresh read of the store is what the screen does on every fetch.
expect(await getOutForDeliveryOrderIds(), contains('1001'));
});
test('completing a stop clears it, so tomorrow starts closed', () async {
await addOutForDeliveryOrderIds(['1001', '1002']);
await removeOutForDeliveryOrderIds(['1001']);
expect(await getOutForDeliveryOrderIds(), {'1002'});
});
});
group('the other line', () {
test('a logistics parcel never has a round to start', () {
ServiceProfile.setActive(ServiceProfile.parcel);
// Its collected parcel goes to a hub and somebody else delivers it, so
// the rider must never be shown a control claiming he has set off.
expect(ServiceProfile.active.deliversToCustomer, isFalse);
expect(
MilkRun.navigatesToCustomer(order('1001'), collectedIds: {'1001'}),
isFalse,
);
});
});
}