import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:emergency/app.dart'; import 'package:emergency/features/home/widgets/emergency_button.dart'; import 'package:emergency/repositories/emergency_number_repository.dart'; import 'package:emergency/services/country_code_sources/country_code_source.dart'; import 'package:emergency/services/location_service.dart'; /// Einfache manuelle Fake-Quelle statt Mocking-Package (siehe AP4-Vorgabe: /// kein neues Mocking-Package einführen), analog zu /// `test/services/location_service_test.dart`. class _FakeSource implements CountryCodeSource { _FakeSource(this._result); final String? _result; @override Future resolve() async => _result; } /// Fake-Cache: Verhindert, dass `LocationService` beim Cachen eines /// SIM/GPS-Treffers den echten `shared_preferences`-Plugin-Kanal anspricht /// (der ohne Mock-Setup in reinen Widget-Tests nicht antwortet). class _FakeCache implements CountryCodeCache { @override Future resolve() async => null; @override Future save(String isoCode) async {} } /// Analog zu `_FakeCache`, aber für die manuelle Auswahl (AP6): verhindert /// den echten `shared_preferences`-Zugriff, den `LocationService` seit AP6 /// als vorgeschaltete Prioritätsstufe abfragt. class _FakeManualSource implements ManualCountryCodeStore { @override Future resolve() async => null; @override Future save(String? isoCode) async {} } void main() { testWidgets('HomeScreen zeigt nach dem Laden mindestens einen EmergencyButton für DE', ( WidgetTester tester, ) async { // Asset-Laden über rootBundle ist echte I/O und läuft nicht innerhalb des // FakeAsync-Zeitrahmens von pump()/pumpAndSettle() durch. Deshalb wird // die Datenbasis hier vorab über runAsync geladen (Repository.load() ist // danach idempotent, s. Repository). Die Ländererkennung selbst wird // über eine gefakte SIM-Quelle deterministisch auf "DE" gesetzt, damit // der Test nicht von echten Plattform-Kanälen (SIM/GPS/Cache) abhängt. final repository = EmergencyNumberRepository(); await tester.runAsync(() => repository.load()); // gpsSource muss explizit gesetzt werden: Ohne eigenen Wert würde // LocationService() intern ein echtes GpsCountryCodeSource (und damit // Geocoding()) konstruieren, was ohne registriertes Platform-Interface // sofort wirft (siehe gps_country_code_source_test.dart). cacheSource // wird ebenfalls gefaked, siehe _FakeCache. final locationService = LocationService( simSource: _FakeSource('DE'), gpsSource: _FakeSource(null), cacheSource: _FakeCache(), manualSource: _FakeManualSource(), ); await tester.pumpWidget(App(repository: repository, locationService: locationService)); await tester.pumpAndSettle(); expect(find.byType(EmergencyButton), findsWidgets); // DE führt "112" bereits als general-Nummer, daher darf der globale // Panik-Button hier nicht zusätzlich dieselbe Nummer anzeigen (Dedup). expect(find.text('112'), findsOneWidget); expect(find.byKey(const Key('panicButton')), findsNothing); }); testWidgets( 'HomeScreen zeigt den globalen Panik-Button bereits während des Ladens der Ländererkennung', (WidgetTester tester) async { // Bewusst kein runAsync/Vorladen des Repositories: Der Ladezustand // (EmergencyStatus.initializing) soll direkt nach pumpWidget // beobachtbar sein, ohne auf das Ende des echten Asset-Ladens zu warten. // Die Ländererkennung wird ohnehin nie erreicht (blockiert beim // Repository-Laden), locationService wird trotzdem explizit gefaked, // siehe Kommentar im Test oben. await tester.pumpWidget( App( repository: EmergencyNumberRepository(), locationService: LocationService( simSource: _FakeSource(null), gpsSource: _FakeSource(null), cacheSource: _FakeCache(), manualSource: _FakeManualSource(), ), ), ); expect(find.byType(CircularProgressIndicator), findsOneWidget); expect(find.byKey(const Key('panicButton')), findsOneWidget); expect(find.text('112'), findsOneWidget); }, ); }