Implementiert den kompletten Kern-Flow der Emergency App gemäß docs/plan.md: - Notrufnummern-Datenbasis für 199 Länder + Modelle/Repository (AP1) - DialerService für tel:-Notrufe ohne Auto-Dial (AP2) - Statisches UI mit Panik-Button-Fallback (AP3) - Priorisierte Ländererkennung: SIM/Netz -> GPS/Geocoding -> Cache (AP4) - EmergencyProvider verdrahtet Repository/LocationService mit der UI (AP5) - Manuelle Länderauswahl als Fallback samt eigener Priorität (AP6) - UI-Lokalisierung (de/en/fr/es), an erkanntes Land gekoppelt (AP7) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
92 lines
3.0 KiB
Dart
92 lines
3.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:emergency/app.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';
|
|
|
|
/// Siehe `test/widget_test.dart` für die Begründung dieser Fakes
|
|
/// (deterministische Ländererkennung ohne echte Plattform-Kanäle).
|
|
class _FakeSource implements CountryCodeSource {
|
|
_FakeSource(this._result);
|
|
|
|
final String? _result;
|
|
|
|
@override
|
|
Future<String?> resolve() async => _result;
|
|
}
|
|
|
|
class _FakeCache implements CountryCodeCache {
|
|
@override
|
|
Future<String?> resolve() async => null;
|
|
|
|
@override
|
|
Future<void> save(String isoCode) async {}
|
|
}
|
|
|
|
class _FakeManualSource implements ManualCountryCodeStore {
|
|
@override
|
|
Future<String?> resolve() async => null;
|
|
|
|
@override
|
|
Future<void> save(String? isoCode) async {}
|
|
}
|
|
|
|
/// AP7: Verifiziert, dass die sichtbare App-Sprache tatsächlich an das
|
|
/// erkannte Land gekoppelt ist (`docs/plan.md`, Abschnitt 2 + 8), nicht nur,
|
|
/// dass `resolveAppLocale` als reine Funktion korrekt rechnet
|
|
/// (`test/core/country_locale_map_test.dart`).
|
|
Future<void> _pumpAppWithCountry(WidgetTester tester, String? isoCode) async {
|
|
final repository = EmergencyNumberRepository();
|
|
await tester.runAsync(() => repository.load());
|
|
final locationService = LocationService(
|
|
simSource: _FakeSource(isoCode),
|
|
gpsSource: _FakeSource(null),
|
|
cacheSource: _FakeCache(),
|
|
manualSource: _FakeManualSource(),
|
|
);
|
|
|
|
await tester.pumpWidget(App(repository: repository, locationService: locationService));
|
|
await tester.pumpAndSettle();
|
|
}
|
|
|
|
/// Findet Text konkret innerhalb der `AppBar`, nicht irgendwo im Baum:
|
|
/// Der Notrufnummern-Datensatz mancher Länder (z. B. DE: "Notruf", US:
|
|
/// "Emergency") verwendet zufällig denselben Text wie der übersetzte
|
|
/// AppBar-Titel, ein ungebundener `find.text(...)` wäre daher mehrdeutig.
|
|
Finder _appBarText(String text) =>
|
|
find.descendant(of: find.byType(AppBar), matching: find.text(text));
|
|
|
|
void main() {
|
|
testWidgets('DE wird erkannt -> AppBar-Titel erscheint auf Deutsch ("Notruf")', (tester) async {
|
|
await _pumpAppWithCountry(tester, 'DE');
|
|
|
|
expect(_appBarText('Notruf'), findsOneWidget);
|
|
expect(_appBarText('Emergency'), findsNothing);
|
|
});
|
|
|
|
testWidgets('US wird erkannt -> AppBar-Titel erscheint auf Englisch ("Emergency")', (
|
|
tester,
|
|
) async {
|
|
await _pumpAppWithCountry(tester, 'US');
|
|
|
|
expect(_appBarText('Emergency'), findsOneWidget);
|
|
expect(_appBarText('Notruf'), findsNothing);
|
|
});
|
|
|
|
testWidgets('FR wird erkannt -> AppBar-Titel erscheint auf Französisch ("Urgence")', (
|
|
tester,
|
|
) async {
|
|
await _pumpAppWithCountry(tester, 'FR');
|
|
|
|
expect(_appBarText('Urgence'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('Land nicht ermittelbar -> Fallback auf Englisch ("Emergency")', (tester) async {
|
|
await _pumpAppWithCountry(tester, null);
|
|
|
|
expect(_appBarText('Emergency'), findsOneWidget);
|
|
});
|
|
}
|