179 lines
6.5 KiB
Dart
179 lines
6.5 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:miler/Models/stop_status.dart';
|
|
import 'package:miler/data/order_manifest.dart';
|
|
import 'package:miler/data/service_profile.dart';
|
|
import 'package:miler/views/Dashboard/home/duty_sheet.dart';
|
|
import 'package:miler/views/Dashboard/home/stop_action_sheet.dart';
|
|
import 'package:miler/views/helpers/constants/Colorconstants.dart';
|
|
import 'package:miler/views/helpers/widgets/miler_sheet_kit.dart';
|
|
|
|
/// ─────────────────────────────────────────────────────────────────────────
|
|
/// THE SHEET KIT — the rules, held
|
|
///
|
|
/// The kit exists because six presentation styles had grown around one kind
|
|
/// of surface (see the audit in `miler_sheet_kit.dart`). What stops a seventh
|
|
/// growing back is not the kit's existence but these tests: the shared handle
|
|
/// on the sheets a rider actually uses, and the one inset rule that prevents
|
|
/// the double-SafeArea CTA drift from returning.
|
|
/// ─────────────────────────────────────────────────────────────────────────
|
|
void main() {
|
|
tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel));
|
|
|
|
Future<void> pump(
|
|
WidgetTester tester,
|
|
Widget child, {
|
|
EdgeInsets viewInsets = EdgeInsets.zero,
|
|
EdgeInsets viewPadding = EdgeInsets.zero,
|
|
}) async {
|
|
tester.view.physicalSize = const Size(1170, 2532);
|
|
tester.view.devicePixelRatio = 3.0;
|
|
addTearDown(tester.view.reset);
|
|
|
|
await tester.pumpWidget(
|
|
ScreenUtilInit(
|
|
designSize: const Size(390, 844),
|
|
builder: (_, _) => MaterialApp(
|
|
home: MediaQuery(
|
|
data: MediaQueryData(
|
|
size: const Size(390, 844),
|
|
viewInsets: viewInsets,
|
|
viewPadding: viewPadding,
|
|
),
|
|
// NOT a Scaffold: `resizeToAvoidBottomInset` consumes viewInsets
|
|
// before the sheet sees them, which is exactly the environment a
|
|
// modal route does NOT provide — the sheet must read the keyboard
|
|
// itself, which is the behaviour under test.
|
|
child: Material(
|
|
color: Colors.black,
|
|
child: Align(alignment: Alignment.bottomCenter, child: child),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pump();
|
|
}
|
|
|
|
group('the scaffold', () {
|
|
testWidgets('pays the larger of keyboard and gesture bar, never both', (
|
|
tester,
|
|
) async {
|
|
// A gesture-bar phone with the keyboard up. The old double-SafeArea bug
|
|
// paid 300 + 34; the rule is max(300, 34).
|
|
await pump(
|
|
tester,
|
|
const MilerSheetScaffold(child: SizedBox(height: 40)),
|
|
viewInsets: const EdgeInsets.only(bottom: 300),
|
|
viewPadding: const EdgeInsets.only(bottom: 34),
|
|
);
|
|
|
|
final padding = tester.widget<AnimatedPadding>(
|
|
find.byType(AnimatedPadding).first,
|
|
);
|
|
expect(
|
|
padding.padding,
|
|
const EdgeInsets.only(bottom: 300),
|
|
reason:
|
|
'the keyboard replaces the gesture bar — summing them floats '
|
|
'the CTA a bar height above the keyboard',
|
|
);
|
|
});
|
|
|
|
testWidgets('with no keyboard the gesture bar is still paid', (
|
|
tester,
|
|
) async {
|
|
await pump(
|
|
tester,
|
|
const MilerSheetScaffold(child: SizedBox(height: 40)),
|
|
viewPadding: const EdgeInsets.only(bottom: 34),
|
|
);
|
|
|
|
final padding = tester.widget<AnimatedPadding>(
|
|
find.byType(AnimatedPadding).first,
|
|
);
|
|
expect(padding.padding, const EdgeInsets.only(bottom: 34));
|
|
});
|
|
|
|
testWidgets('draws the shared handle once', (tester) async {
|
|
await pump(tester, const MilerSheetScaffold(child: SizedBox(height: 40)));
|
|
expect(find.byType(MilerSheetHandle), findsOneWidget);
|
|
});
|
|
});
|
|
|
|
group('the migrated sheets carry the kit', () {
|
|
testWidgets('duty', (tester) async {
|
|
await pump(
|
|
tester,
|
|
DutySheet(goingOnline: true, onConfirm: () async => false),
|
|
);
|
|
expect(find.byType(MilerSheetScaffold), findsOneWidget);
|
|
expect(find.byType(MilerSheetHandle), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('the rung confirmation', (tester) async {
|
|
ServiceProfile.setActive(ServiceProfile.milkMan);
|
|
await pump(
|
|
tester,
|
|
StopActionSheet(
|
|
stage: StopStatus.accepted,
|
|
placeName: 'Vidhya Kitchen',
|
|
count: 2,
|
|
lines: const [
|
|
ManifestLine(stop: {}, orderId: 'A', customer: 'Joe', label: 'Bag 1'),
|
|
ManifestLine(stop: {}, orderId: 'B', customer: 'Arun', label: 'Bag 2'),
|
|
],
|
|
onConfirm: (_) async => null,
|
|
),
|
|
);
|
|
expect(find.byType(MilerSheetScaffold), findsOneWidget);
|
|
expect(find.byType(MilerSheetHandle), findsOneWidget);
|
|
// The manifest is still the sheet's content — the kit wraps, it does
|
|
// not swallow.
|
|
expect(find.text('Joe'), findsOneWidget);
|
|
expect(find.text('Bag 2'), findsOneWidget);
|
|
});
|
|
});
|
|
|
|
group('the choice row', () {
|
|
testWidgets('selection is a soft fill and a tick, not a slab', (
|
|
tester,
|
|
) async {
|
|
await pump(
|
|
tester,
|
|
Material(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: const [
|
|
MilerSheetChoiceRow(label: 'Wrong address', selected: true),
|
|
MilerSheetChoiceRow(label: 'Out of area', selected: false),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
|
|
// The tick marks the chosen answer…
|
|
expect(find.byIcon(LucideIcons.check), findsNWidgets(2));
|
|
final ticks = tester
|
|
.widgetList<AnimatedOpacity>(find.byType(AnimatedOpacity))
|
|
.map((w) => w.opacity)
|
|
.toList();
|
|
expect(ticks, [
|
|
1.0,
|
|
0.0,
|
|
], reason: 'the tick shows on the selected row and only there');
|
|
|
|
// …and no row is ever a full-strength primary slab. The fill that broke
|
|
// this rule outshouted the destructive CTA under it.
|
|
final fills = tester
|
|
.widgetList<AnimatedContainer>(find.byType(AnimatedContainer))
|
|
.map((c) => (c.decoration as BoxDecoration?)?.color)
|
|
.whereType<Color>();
|
|
expect(fills, isNot(contains(ColorConstants.primary)));
|
|
});
|
|
});
|
|
}
|