import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:rippr/main.dart' as app; /// End-to-end tests against the real app on a real device or simulator. /// /// These exist to cover what widget tests structurally cannot: that Drift actually opens /// against platform storage, that the plugin registrations resolve, that go_router /// navigates a real Navigator, and that the app survives a cold start. /// /// **What these still cannot prove.** Neither simulator produces velocity — `adb emu geo /// fix` teleports and iOS's simulated locations are no better — so max speed, moving /// time, average moving speed and speed colouring on the map remain unverifiable here. /// A green run of this file says nothing about any of them. That is what T25's real ride /// is for; see `docs/port/PLAN.md` and the native repo's `docs/TESTING.md`. /// /// Run with: /// flutter test integration_test -d `` void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('cold start', () { testWidgets('the app launches and lands on the record screen', (tester) async { app.main(); await tester.pumpAndSettle(const Duration(seconds: 5)); expect(find.text('RIPPR'), findsOneWidget); expect(find.text('SPEED'), findsOneWidget); // Idle, because a fresh install has no ride in progress. expect(find.text('Ready'), findsOneWidget); }); testWidgets('the database opens against real platform storage', (tester) async { // If Drift could not open its file, or the sqlite3 native library were missing, // the trips list would surface an error rather than an empty state. This is the // check a widget test with an in-memory database cannot make. app.main(); await tester.pumpAndSettle(const Duration(seconds: 5)); await tester.tap(find.text('Rides')); await tester.pumpAndSettle(); expect(find.textContaining('No rides yet'), findsOneWidget); }); }); group('navigation', () { testWidgets('record → rides → back', (tester) async { app.main(); await tester.pumpAndSettle(const Duration(seconds: 5)); await tester.tap(find.text('Rides')); await tester.pumpAndSettle(); expect(find.text('RIDES'), findsOneWidget); await tester.tap(find.byKey(const Key('back'))); await tester.pumpAndSettle(); expect(find.text('SPEED'), findsOneWidget); }); }); group('permissions', () { testWidgets('starting without location permission explains itself', (tester) async { // On a simulator with permission denied, Start must surface a readable message // rather than silently doing nothing or throwing into the void. // // If permission IS granted in the test environment, recording begins instead — // both are acceptable outcomes, so this asserts only that the app stays alive and // responsive either way. app.main(); await tester.pumpAndSettle(const Duration(seconds: 5)); await tester.tap(find.byKey(const Key('start'))); await tester.pumpAndSettle(const Duration(seconds: 3)); expect(tester.takeException(), isNull); expect(find.byType(MaterialApp), findsOneWidget); }); }); }