Files
doormile_milderapp/test/skip_leaves_deliveries_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

123 lines
5.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
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/service_profile.dart';
/// ─────────────────────────────────────────────────────────────────────────
/// A SKIPPED DELIVERY IS DONE WITH, NOT PARKED
///
/// ── The regression ──
///
/// A skip at a customer's door left the tab and came back. The in-memory set
/// that holds a just-finished stop off the list is what was doing the work,
/// and it dies with the process — so the next cold start put the stop the
/// rider had written off an hour earlier back at the top of his queue, while
/// its record sat in Activity saying otherwise.
///
/// It is specifically a *skip* problem. A delivery closes the consignment, so
/// the backend stops calling it delivery work within a poll or two and the row
/// drops out on its own. A skip is a failed attempt: the server rightly leaves
/// the consignment `Out_for_Delivery`, and it will keep coming back for as long
/// as the day lasts unless the device remembers what it did.
///
/// These pin the store rules that hold it off the tab and put it on Activity
/// under its own word.
/// ─────────────────────────────────────────────────────────────────────────
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
setUp(() {
SharedPreferences.setMockInitialValues({'userid': 38});
ServiceProfile.setActive(ServiceProfile.milkMan);
});
tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel));
Map<String, dynamic> stop(String id) => {
'orderid': id,
'pickupid': int.parse(id),
'orderstatus': 'outfordelivery',
'pickupcustomer': 'SEQTEST Ukkadam',
};
group('the record', () {
test(
'a skip is filed as a skip, not flattened into a cancellation',
() async {
await addCompletedBookings([stop('1001')], terminalStatus: 'skipped');
final filed = (await getCompletedBookings()).single;
expect(stopStatusOf(filed).isSkipped, isTrue);
expect(
stopStatusOf(filed).isCancelled,
isFalse,
reason:
'a stop the rider walked away from and one the office called '
'off are different things, and Activity slices them apart',
);
},
);
test('the exact word wins over the cancelled shorthand', () async {
// `cancelled: true` is what suppresses the "delivery N of M" toast, so
// the skip path passes both — and the precise word has to survive.
await addCompletedBookings(
[stop('1001')],
cancelled: true,
terminalStatus: 'skipped',
);
expect((await getCompletedBookings()).single['orderstatus'], 'skipped');
});
test('a real cancellation still files as cancelled', () async {
await addCompletedBookings([stop('1001')], cancelled: true);
expect((await getCompletedBookings()).single['orderstatus'], 'cancelled');
});
test('a delivery still files as delivered', () async {
await addCompletedBookings([stop('1001')]);
expect(
(await getCompletedBookings()).single['orderstatus'],
'delivered',
reason: 'the milk run ends at the customer, not at a hub',
);
});
});
group('it stays off the deliveries tab', () {
test('the closed set survives the process that wrote it', () async {
await addCompletedBookings([stop('1001')], terminalStatus: 'skipped');
// What a cold start reads back — the same call the Deliveries tab makes
// to rebuild its just-finished set.
expect(await getCompletedOrderIds(), contains('1001'));
});
test('closing one stop does not close the rest of the load', () async {
await addCompletedBookings([stop('1001')], terminalStatus: 'skipped');
expect(await getCompletedOrderIds(), isNot(contains('1002')));
});
test('yesterday’s skip is not today’s work', () async {
// Pruned on read, like every other record in this store: a skip the
// rider can no longer act on must not hold a stop off tomorrow's tab.
await addCompletedBookings([stop('1001')], terminalStatus: 'skipped');
final aged = (await getCompletedBookings())
.map((b) => {...b, 'completedday': '2020-01-01'})
.toList();
await debugSeedStore('completed_bookings', jsonEncode(aged));
expect(await getCompletedOrderIds(), isEmpty);
});
test('another rider’s skip is not this one’s', () async {
await addCompletedBookings([stop('1001')], terminalStatus: 'skipped');
SharedPreferences.setMockInitialValues({'userid': 99});
expect(await getCompletedOrderIds(), isEmpty);
});
});
}