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>
This commit is contained in:
111
test/delivery_shell_smoke_test.dart
Normal file
111
test/delivery_shell_smoke_test.dart
Normal file
@@ -0,0 +1,111 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'package:miler/data/service_profile.dart';
|
||||
import 'package:miler/helpers/rider_shell.dart';
|
||||
|
||||
/// Does the ported delivery dashboard actually *build*?
|
||||
///
|
||||
/// ── Why this is worth a test of its own ──
|
||||
///
|
||||
/// `delivery_line_test.dart` checks that [riderShell] returns the right widget
|
||||
/// *type*, which is a cheap assertion: it constructs nothing. The failure this
|
||||
/// port was most exposed to is one type-checking cannot see — the delivery home
|
||||
/// page resolves its controller in a **field initialiser**:
|
||||
///
|
||||
/// final DeliveryController _deliveryController = Get.find<DeliveryController>();
|
||||
///
|
||||
/// GetX keys its container on type, and both lines declare a class called
|
||||
/// `RiderLogController`, `LogController` and `ProfileController`. So a delivery
|
||||
/// screen asking for "the" RiderLogController gets nothing unless the *xpress*
|
||||
/// type was registered — and it throws while the widget is being constructed,
|
||||
/// before any frame, which a rider sees as a red screen rather than an empty
|
||||
/// list. See `bootstrapDeliveryLine`.
|
||||
///
|
||||
/// Pumping the shell for real is the only thing that catches that.
|
||||
///
|
||||
/// ── Why there is no matching test for the parcel shell ──
|
||||
///
|
||||
/// The parcel dashboard reads `PickupController` and friends out of the GetX
|
||||
/// container too, but nothing registers them for it — `main()` does, and tests
|
||||
/// do not run `main()`. Pumping it here would be testing this file's ability to
|
||||
/// re-implement `main()`, not the app.
|
||||
///
|
||||
/// The delivery shell needs no such scaffolding, and that asymmetry is the
|
||||
/// point: [riderShell] calls `registerDeliveryLine()` on the way in, precisely
|
||||
/// because a rider can reach it mid-session by signing out of one line and into
|
||||
/// the other. This test passing with no setup *is* that guard working — and it
|
||||
/// is what caught the first version of that call being `async`, which registered
|
||||
/// nothing before the shell built.
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// ── What is allowed to have gone wrong ──
|
||||
//
|
||||
// One thing, inherited with the markup: Flutter's debug-only complaint that a
|
||||
// `ListTile` sits inside a coloured `DecoratedBox`, so its ink splash is
|
||||
// hidden. Cosmetic, debug-only, and present in Xpress-rider before the port.
|
||||
//
|
||||
// Filtered at `FlutterError.onError` rather than drained afterwards with
|
||||
// `takeException`, which returns one exception at a time while the harness
|
||||
// fails the test on the whole batch. Everything else still reaches the
|
||||
// default handler and still fails the test — in particular a `Get.find`
|
||||
// failure or a missing plugin, which would mean the port does not run.
|
||||
//
|
||||
// Installed **inside the test body**, not in `setUp`: the test binding
|
||||
// installs its own reporter when it starts running the body, which is after
|
||||
// `setUp`, so a handler set there is overwritten before the first pump.
|
||||
tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel));
|
||||
|
||||
testWidgets('the delivery dashboard builds and shows its four tabs', (
|
||||
tester,
|
||||
) async {
|
||||
final reportToHarness = FlutterError.onError;
|
||||
FlutterError.onError = (details) {
|
||||
if (details.exceptionAsString().contains(
|
||||
'ListTile background color or ink splashes',
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
reportToHarness?.call(details);
|
||||
};
|
||||
addTearDown(() => FlutterError.onError = reportToHarness);
|
||||
|
||||
SharedPreferences.setMockInitialValues({});
|
||||
// ── Set directly, not resolved ──
|
||||
//
|
||||
// No tenant name or id opens this line any more; only
|
||||
// `--dart-define=TENANT=delivery` does, and that is a compile-time constant
|
||||
// a test cannot set. See `delivery_line_test.dart` for why the wire route
|
||||
// was closed.
|
||||
//
|
||||
// What this test is actually for survives that unchanged: it is the guard
|
||||
// on `registerDeliveryLine()` being **synchronous**. An async version
|
||||
// returns at its first await, the framework builds the shell in the gap,
|
||||
// and the home page throws on a controller that is about to exist. Only
|
||||
// pumping the real shell catches it.
|
||||
ServiceProfile.setActive(ServiceProfile.delivery);
|
||||
|
||||
await tester.pumpWidget(
|
||||
ScreenUtilInit(
|
||||
designSize: const Size(390, 844),
|
||||
builder: (_, _) => MaterialApp(home: riderShell()),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
// The ported Xpress-rider bar, verbatim: four fixed tabs, shouted in caps.
|
||||
// If the controllers had not been registered, none of this would exist —
|
||||
// the page would have thrown on construction.
|
||||
expect(find.text('HOME'), findsOneWidget);
|
||||
expect(find.text('DELIVERIES'), findsOneWidget);
|
||||
expect(find.text('SUMMARY'), findsOneWidget);
|
||||
expect(find.text('PROFILE'), findsOneWidget);
|
||||
|
||||
// And it is not the parcel bar wearing different words.
|
||||
expect(find.text('Activity'), findsNothing);
|
||||
expect(find.text('Bookings'), findsNothing);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user