MotorSignal-App/test/rider_safety_entitlement_te...

142 lines
4.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:motorcycle_dash/features/entitlements/widgets/pro_lock_badge.dart';
import 'package:motorcycle_dash/features/rides/ride_state_machine.dart';
import 'package:motorcycle_dash/services/billing/product_catalog.dart';
import 'package:motorcycle_dash/services/entitlements/entitlement_state.dart';
import 'package:motorcycle_dash/services/entitlements/feature_access_service.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('Rider Safety & Entitlement Separation Tests', () {
testWidgets(
'suppresses modal upgrade sheet and shows passive snackbar during active ride',
(tester) async {
final activeRidingSession = RideSession(
state: RideState.riding,
tripDistanceMiles: 5.2,
);
await tester.pumpWidget(
ProviderScope(
overrides: [
rideStateMachineProvider.overrideWith(
(ref) => _FakeRideStateMachine(activeRidingSession),
),
],
child: MaterialApp(
home: Scaffold(
body: Consumer(
builder: (context, ref, _) {
return ElevatedButton(
onPressed: () => showProUpgradeSheet(
context,
ref,
feature: MotorSignalFeature.csvExport,
),
child: const Text('TRIGGER UPGRADE'),
);
},
),
),
),
),
);
// Tap the button that triggers upgrade sheet
await tester.tap(find.text('TRIGGER UPGRADE'));
await tester.pump();
// Ensure NO modal bottom sheet appeared
expect(find.byType(BottomSheet), findsNothing);
// Ensure non-blocking passive snackbar appeared
expect(
find.text('Pro feature locked. Upgrade available when stopped.'),
findsOneWidget,
);
},
);
testWidgets('allows modal upgrade sheet when rider is idle / stopped', (
tester,
) async {
final idleSession = RideSession(state: RideState.idle);
await tester.pumpWidget(
ProviderScope(
overrides: [
rideStateMachineProvider.overrideWith(
(ref) => _FakeRideStateMachine(idleSession),
),
],
child: MaterialApp(
home: Scaffold(
body: Consumer(
builder: (context, ref, _) {
return ElevatedButton(
onPressed: () => showProUpgradeSheet(
context,
ref,
feature: MotorSignalFeature.csvExport,
),
child: const Text('TRIGGER UPGRADE'),
);
},
),
),
),
),
);
// Tap the button that triggers upgrade sheet
await tester.tap(find.text('TRIGGER UPGRADE'));
await tester.pumpAndSettle();
// Ensure modal bottom sheet DID open
expect(find.byType(BottomSheet), findsOneWidget);
expect(find.text('Forensic CSV & PDF Export'), findsOneWidget);
expect(find.text('VIEW MOTORSIGNAL PRO'), findsOneWidget);
expect(find.text('NOT NOW'), findsOneWidget);
});
test('Entitlement state changes do not disrupt RideSession or RideState', () {
final activeSession = RideSession(
state: RideState.riding,
tripDistanceMiles: 12.4,
topSpeedMph: 64.0,
);
// Verify that changing EntitlementState from Free to Pro to Expired is independent of RideSession
var entitlement = const EntitlementState.free();
expect(entitlement.isPro, isFalse);
expect(activeSession.state, RideState.riding);
entitlement = EntitlementState.proMonthlyActive(
productId: ProductCatalog.proMonthly,
);
expect(entitlement.isPro, isTrue);
expect(activeSession.state, RideState.riding);
entitlement = EntitlementState.normalized(
plan: MotorSignalPlan.proMonthly,
status: MotorSignalEntitlementStatus.proMonthlyExpired,
verificationStatus: EntitlementVerificationStatus.expired,
);
expect(entitlement.isPro, isFalse);
expect(activeSession.state, RideState.riding);
expect(activeSession.tripDistanceMiles, 12.4);
});
});
}
class _FakeRideStateMachine extends StateNotifier<RideSession>
implements RideStateMachine {
_FakeRideStateMachine(super.initialState);
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}