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

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);
});
}