162 lines
6.2 KiB
Dart
162 lines
6.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:miler/data/service_profile.dart';
|
|
import 'package:miler/views/Dashboard/home/trip.dart';
|
|
import 'package:miler/views/Dashboard/home/trip_card.dart';
|
|
|
|
/// ─────────────────────────────────────────────────────────────────────────
|
|
/// A STOP HE IS STANDING AT MUST NOT LEAVE THE SCREEN
|
|
///
|
|
/// Reported from a live run: the rider marked **Arrived**, the console updated
|
|
/// correctly — and the stop vanished off Home. Deliveries did not have it
|
|
/// either, and could not: arrival is a *pre-pickup* rung, and the delivery tab
|
|
/// only takes work once it is collected. The stop existed in neither place.
|
|
///
|
|
/// ── What caused it ──
|
|
///
|
|
/// Nothing on the backend. [StopState.arrived] and [StopState.active] used to
|
|
/// be one value, and `TripCard._showsOnHome` — like a dozen other sites — asked
|
|
/// `state == StopState.active` to mean *is he at the counter*. Splitting the
|
|
/// two apart so the row could say **Arrived** instead of **Active** left every
|
|
/// one of those comparisons answering `false` for the new rung.
|
|
///
|
|
/// The visibility filter was the one the rider could see. The others were just
|
|
/// as broken and quieter: the selection bar offered *Accept* for a stop he was
|
|
/// already at, the card stopped building its **Mark as picked** button, and the
|
|
/// group he was working no longer opened by default.
|
|
///
|
|
/// These pin the rung end to end — the predicate that now answers the question
|
|
/// once ([StopStateX.isAtSource]), and the screen behaviour that regressed.
|
|
/// ─────────────────────────────────────────────────────────────────────────
|
|
void main() {
|
|
tearDown(() => ServiceProfile.setActive(ServiceProfile.parcel));
|
|
|
|
Map<String, dynamic> meal(String id, String who, {String? status}) => {
|
|
'orderid': id,
|
|
'type': 'delivery',
|
|
'step': int.parse(id),
|
|
'pickupcustomer': who,
|
|
'kitchenid': 'K1',
|
|
'kitchenname': 'Vidhya Kitchen',
|
|
'sourcename': 'Vidhya Kitchen',
|
|
'pickupcontactno': '9787698259',
|
|
'pickupaddress': '4 Cross, RS Puram, Coimbatore',
|
|
'dropaddress': '12 SNS Colony, Peelamedu, Coimbatore 641004',
|
|
'Quantity': '1',
|
|
if (status != null) 'orderstatus': status,
|
|
};
|
|
|
|
Future<void> pumpHome(
|
|
WidgetTester tester,
|
|
List<Map<String, dynamic>> stops,
|
|
) async {
|
|
ServiceProfile.setActive(ServiceProfile.milkMan);
|
|
tester.view.physicalSize = const Size(390 * 3, 2600 * 3);
|
|
tester.view.devicePixelRatio = 3.0;
|
|
addTearDown(tester.view.reset);
|
|
|
|
await tester.pumpWidget(
|
|
ScreenUtilInit(
|
|
designSize: const Size(390, 844),
|
|
builder: (_, _) => MaterialApp(
|
|
home: Scaffold(
|
|
body: SingleChildScrollView(
|
|
child: TripCard(
|
|
trip: Trip.fromStops(id: 'run', stops: stops),
|
|
acceptedIds: const {},
|
|
selectedIds: const {},
|
|
onToggleSelect: (_) {},
|
|
onSelectAll: (_) {},
|
|
onStopTap: (_) {},
|
|
onCallStop: (_) {},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
// Not `pumpAndSettle`: an arrived row is a **live** row, and [LiveMark]
|
|
// pulses for as long as it is on screen — settling waits for an animation
|
|
// that is never going to stop. Two pumps lay the frame out and let the
|
|
// pulse start, which is all these assertions need.
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 300));
|
|
}
|
|
|
|
group('1 · the predicate that answers it once', () {
|
|
test('arrived and active both mean "he is at the source"', () {
|
|
expect(StopState.arrived.isAtSource, isTrue);
|
|
expect(StopState.active.isAtSource, isTrue);
|
|
});
|
|
|
|
test('and nothing else does', () {
|
|
for (final other in const [
|
|
StopState.pending,
|
|
StopState.accepted,
|
|
StopState.collected,
|
|
StopState.done,
|
|
StopState.skipped,
|
|
StopState.rejected,
|
|
]) {
|
|
expect(
|
|
other.isAtSource,
|
|
isFalse,
|
|
reason: '$other must not read as standing at the counter',
|
|
);
|
|
}
|
|
});
|
|
|
|
test('an arrived stop is committed work, not an open offer', () {
|
|
// It rode in on `active` and was dropped by the same split. A rider who
|
|
// has reported an arrival has plainly committed to the stop.
|
|
expect(StopState.arrived.isCommitted, isTrue);
|
|
expect(StopState.pending.isCommitted, isFalse);
|
|
});
|
|
});
|
|
|
|
group('2 · the screen behaviour that regressed', () {
|
|
testWidgets('an arrived stop stays on Home', (tester) async {
|
|
await pumpHome(tester, [
|
|
meal('1', 'Joe Mathew', status: 'arrived'),
|
|
meal('2', 'Arun Prakash'),
|
|
]);
|
|
|
|
expect(
|
|
find.text('Joe Mathew'),
|
|
findsOneWidget,
|
|
reason:
|
|
'the rider is standing at this counter — it cannot leave Home, '
|
|
'and Deliveries will not take it until it is collected',
|
|
);
|
|
});
|
|
|
|
testWidgets('it is still there beside an untouched stop', (tester) async {
|
|
// Guards the opposite overcorrection: making arrived visible must not
|
|
// have cost the ordinary rows their place in the run.
|
|
await pumpHome(tester, [
|
|
meal('1', 'Joe Mathew', status: 'arrived'),
|
|
meal('2', 'Arun Prakash'),
|
|
]);
|
|
|
|
expect(find.text('Joe Mathew'), findsOneWidget);
|
|
expect(find.text('Arun Prakash'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('a collected stop still leaves — that one is not a bug', (
|
|
tester,
|
|
) async {
|
|
// The filter's real job, asserted so a fix for the disappearance cannot
|
|
// quietly turn into "nothing ever leaves Home".
|
|
await pumpHome(tester, [
|
|
meal('1', 'Joe Mathew', status: 'picked'),
|
|
meal('2', 'Arun Prakash'),
|
|
]);
|
|
|
|
expect(find.text('Joe Mathew'), findsNothing);
|
|
expect(find.text('Arun Prakash'), findsOneWidget);
|
|
});
|
|
});
|
|
}
|