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>
109 lines
3.7 KiB
Dart
109 lines
3.7 KiB
Dart
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/views/Dashboard/activity/activity_page.dart';
|
||
import 'package:miler/views/Dashboard/summary/summary.dart';
|
||
import 'package:miler/views/offline/offline_banner.dart';
|
||
|
||
/// ── Riders turn the system font up ──
|
||
///
|
||
/// An audit found the screens with layout tests (verify, collect payment,
|
||
/// profile, trip tabs) solid at 2×, and everything else unguarded: 443 `Text`
|
||
/// widgets against 109 `maxLines`, and exactly one file in 102 reading the text
|
||
/// scaler.
|
||
///
|
||
/// The failure mode is not cosmetic. A `Row` with a fixed-width child overflows
|
||
/// into the black-and-yellow stripe bar, which on a customer's doorstep looks
|
||
/// like the app has crashed. Earnings was the worst of them — a 46sp hero
|
||
/// figure sharing a row with labels — which is why that figure is now on the
|
||
/// type scale.
|
||
///
|
||
/// This sweeps the screens that had no coverage. It asserts no exception is
|
||
/// thrown, which is exactly what a `RenderFlex` overflow does.
|
||
void main() {
|
||
Future<void> pump(
|
||
WidgetTester tester,
|
||
Widget page, {
|
||
double width = 360,
|
||
double scale = 1.0,
|
||
}) async {
|
||
tester.view.physicalSize = Size(width * 3, 780 * 3);
|
||
tester.view.devicePixelRatio = 3.0;
|
||
addTearDown(tester.view.reset);
|
||
|
||
await tester.pumpWidget(
|
||
ScreenUtilInit(
|
||
designSize: const Size(390, 844),
|
||
minTextAdapt: true,
|
||
builder: (_, _) => MaterialApp(
|
||
builder: (context, child) => MediaQuery(
|
||
data: MediaQuery.of(
|
||
context,
|
||
).copyWith(textScaler: TextScaler.linear(scale)),
|
||
child: child!,
|
||
),
|
||
home: page,
|
||
),
|
||
),
|
||
);
|
||
await tester.pump(const Duration(milliseconds: 400));
|
||
}
|
||
|
||
// The four scales Android offers, on the narrowest phone the app supports.
|
||
const scales = [1.0, 1.3, 1.5, 2.0];
|
||
|
||
group('Earnings', () {
|
||
for (final s in scales) {
|
||
testWidgets('lays out at ${s}x', (tester) async {
|
||
SharedPreferences.setMockInitialValues({'userId': 1});
|
||
await pump(tester, const Summary(), scale: s);
|
||
expect(tester.takeException(), isNull);
|
||
});
|
||
}
|
||
});
|
||
|
||
group('Activity', () {
|
||
for (final s in scales) {
|
||
testWidgets('lays out at ${s}x', (tester) async {
|
||
SharedPreferences.setMockInitialValues({'userId': 1});
|
||
await pump(tester, const ActivityPage(), scale: s);
|
||
expect(tester.takeException(), isNull);
|
||
});
|
||
}
|
||
});
|
||
|
||
// ── Sign In is covered by `auth_design_test.dart`, not here ──
|
||
//
|
||
// The screen calls `NotificationServce.initialize` in `initState`, which
|
||
// needs a platform channel a widget test has no way to answer. That is a test
|
||
// harness limitation rather than a layout finding: the auth *components* —
|
||
// the code row, the scaffold, the primary button, the inline error — are
|
||
// pumped and asserted directly in `auth_design_test.dart`, which is where the
|
||
// design surface actually lives.
|
||
|
||
group('the offline strip', () {
|
||
for (final s in scales) {
|
||
testWidgets('lays out at ${s}x without covering the job', (tester) async {
|
||
await pump(
|
||
tester,
|
||
const OfflineScope(
|
||
offline: true,
|
||
child: Scaffold(
|
||
body: Center(child: Text('45, Lake View Apartments, Coimbatore')),
|
||
),
|
||
),
|
||
scale: s,
|
||
);
|
||
expect(tester.takeException(), isNull);
|
||
// Still readable, still not on top of anything.
|
||
expect(
|
||
find.text('45, Lake View Apartments, Coimbatore'),
|
||
findsOneWidget,
|
||
);
|
||
});
|
||
}
|
||
});
|
||
}
|