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>
106 lines
3.8 KiB
Dart
106 lines
3.8 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import 'package:miler/data/accepted_store.dart';
|
|
|
|
/// Deleting a mock generator does not reach the rows it already wrote.
|
|
///
|
|
/// Every store in `accepted_store.dart` is SharedPreferences, so a phone that
|
|
/// once ran a build with the demo layer still carries those bookings — and
|
|
/// Bookings merges the accepted store into its list while Activity reads the
|
|
/// completed and skipped ones. That is why demo stops kept appearing on exactly
|
|
/// those two tabs with nothing left in the repo to explain them.
|
|
///
|
|
/// The risk in fixing it is the obvious one: a blanket wipe would take the
|
|
/// rider's real accepted work with it. So these tests are mostly about what
|
|
/// must *survive*.
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
Map<String, dynamic> booking(String id, {String? pickupId}) => {
|
|
'orderid': id,
|
|
if (pickupId != null) 'pickupid': pickupId,
|
|
'pickupcustomer': 'Customer $id',
|
|
'orderstatus': 'accepted',
|
|
};
|
|
|
|
test('drops the demo bookings and keeps the real ones', () async {
|
|
SharedPreferences.setMockInitialValues({});
|
|
await debugSeedStore(
|
|
'mock_accepted_bookings',
|
|
jsonEncode([
|
|
booking('MOCK-Q-1001', pickupId: 'del-mock-q-1001'),
|
|
booking('884213'),
|
|
booking('MOCK-B-3004'),
|
|
]),
|
|
);
|
|
|
|
expect(await purgeDemoRecords(), 2);
|
|
|
|
final left = await getAcceptedBookings();
|
|
expect(left.map((b) => b['orderid']), ['884213']);
|
|
});
|
|
|
|
test('matches on the pickup id too', () async {
|
|
// `getMockQueues` wrote ids like `del-mock-q-1001` on the pickup field
|
|
// while the order id looked ordinary in some rows.
|
|
SharedPreferences.setMockInitialValues({});
|
|
await debugSeedStore(
|
|
'completed_bookings',
|
|
jsonEncode([
|
|
booking('7001', pickupId: 'del-mock-d-2003'),
|
|
booking('7002', pickupId: 'del-77aa'),
|
|
]),
|
|
);
|
|
|
|
expect(await purgeDemoRecords(), 1);
|
|
|
|
// Read the raw store, not [getCompletedBookings]: that reader also drops
|
|
// anything not stamped today, which would empty this list for a reason
|
|
// that has nothing to do with the purge.
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final left =
|
|
(jsonDecode(prefs.getString(await debugStoreKey('completed_bookings'))!)
|
|
as List)
|
|
.map((e) => (e as Map)['orderid'])
|
|
.toList();
|
|
expect(left, ['7002']);
|
|
});
|
|
|
|
test('clears the id-only stores as well', () async {
|
|
SharedPreferences.setMockInitialValues({});
|
|
await debugSeedStore('mock_rejected_order_ids', ['MOCK-Q-1005', '99120']);
|
|
await debugSeedStore('collected_order_ids', ['MOCK-B-3001', '77451']);
|
|
await debugSeedStore('not_loaded_orders', ['DEMO-2', '31009']);
|
|
|
|
expect(await purgeDemoRecords(), 3);
|
|
expect(await getRejectedOrderIds(), {'99120'});
|
|
expect(await getCollectedOrderIds(), {'77451'});
|
|
expect(await getNotLoadedOrderIds(), {'31009'});
|
|
});
|
|
|
|
test('a real order id is never mistaken for a demo one', () async {
|
|
// The ids a backend actually issues. None of these may be touched — losing
|
|
// a genuine accepted booking is a rider driving to a door with no record of
|
|
// why, which is far worse than a leftover demo row.
|
|
final real = [
|
|
booking('884213'),
|
|
booking('ORD-2026-000412'),
|
|
booking('DM-99120', pickupId: 'del-77aa'),
|
|
booking('mockingbird-77'), // contains "mock", does not start with it
|
|
];
|
|
SharedPreferences.setMockInitialValues({});
|
|
await debugSeedStore('mock_accepted_bookings', jsonEncode(real));
|
|
|
|
expect(await purgeDemoRecords(), 0);
|
|
expect((await getAcceptedBookings()).length, real.length);
|
|
});
|
|
|
|
test('an untouched install is a no-op', () async {
|
|
SharedPreferences.setMockInitialValues({});
|
|
expect(await purgeDemoRecords(), 0);
|
|
});
|
|
}
|