import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:motorcycle_dash/models/telemetry_sample.dart'; import 'package:motorcycle_dash/features/rides/ride_state_machine.dart'; import 'package:motorcycle_dash/features/dashboard/widgets/evolution_portrait_dashboard.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:motorcycle_dash/features/records/records_service.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); late SharedPreferences prefs; setUp(() async { SharedPreferences.setMockInitialValues({}); prefs = await SharedPreferences.getInstance(); }); Widget buildDashboard({TelemetrySample? telemetry, RideSession? session}) { return ProviderScope( overrides: [ sharedPreferencesProvider.overrideWithValue(prefs), ], child: MaterialApp( home: Scaffold( body: EvolutionPortraitDashboard( currentSpeedMph: 45.0, heading: 180.0, leanAngle: 12.0, accelG: 0.2, lateralG: 0.1, session: session ?? RideSession( state: RideState.riding, startTime: DateTime.now(), tripDistanceMiles: 3.5, topSpeedMph: 55.0, averageSpeedMph: 42.0, maxLeanLeft: 22.0, maxLeanRight: 25.0, maxAccelG: 0.6, maxBrakingG: 0.8, ), telemetry: telemetry, ), ), ), ); } testWidgets('displays GPS LOCKED when accuracy <= 15m and no fake placeholders', (tester) async { final sample = TelemetrySample( timestamp: DateTime.now(), gpsAccuracy: 8.5, ); await tester.pumpWidget(buildDashboard(telemetry: sample)); await tester.pump(); // Truthful GPS expect(find.text('GPS LOCKED'), findsOneWidget); // Placeholders removed expect(find.text('FIXED'), findsNothing); expect(find.text('HEADSET'), findsNothing); expect(find.text('92%'), findsNothing); // RID-3C-2: the visible badge is a health CLAIM, not a RideState claim. This // fixture builds RideSession(state: riding) with the DEFAULT // healthStatus: recordingArmed and no health evidence, so the truthful label // is WARMING UP. RideState.riding alone is never sufficient for RECORDING. // The Stop action remains available throughout - see U2/U9 in // test/rid3c2_truthful_recording_ui_test.dart. expect(find.text('WARMING UP'), findsOneWidget); expect(find.text('RECORDING'), findsNothing); }); testWidgets('displays GPS FAIR when accuracy is 25m', (tester) async { final sample = TelemetrySample( timestamp: DateTime.now(), gpsAccuracy: 25.0, ); await tester.pumpWidget(buildDashboard(telemetry: sample)); await tester.pump(); expect(find.text('GPS FAIR'), findsOneWidget); expect(find.text('HEADSET'), findsNothing); expect(find.text('92%'), findsNothing); }); testWidgets('displays GPS WEAK when accuracy is 50m', (tester) async { final sample = TelemetrySample( timestamp: DateTime.now(), gpsAccuracy: 50.0, ); await tester.pumpWidget(buildDashboard(telemetry: sample)); await tester.pump(); expect(find.text('GPS WEAK'), findsOneWidget); expect(find.text('HEADSET'), findsNothing); }); testWidgets('displays GPS STALE when accuracy exists but fix is older than staleness bound', (tester) async { final sample = TelemetrySample( timestamp: DateTime.now(), gpsAccuracy: 8.5, gpsAgeMs: 5000, ); await tester.pumpWidget(buildDashboard(telemetry: sample)); await tester.pump(); expect(find.text('GPS STALE'), findsOneWidget); }); testWidgets('displays NO GPS when telemetry is null', (tester) async { await tester.pumpWidget(buildDashboard(telemetry: null)); await tester.pump(); expect(find.text('NO GPS'), findsOneWidget); expect(find.text('HEADSET'), findsNothing); expect(find.text('92%'), findsNothing); }); }