import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:nuvolari/core/region/geo.dart'; import 'package:nuvolari/core/region/region_config.dart'; import 'package:nuvolari/core/region/region_repository.dart'; import 'package:nuvolari/features/places/location_service.dart'; import 'package:nuvolari/features/places/places_repository.dart'; import 'package:nuvolari/features/places/saved_places.dart'; import 'package:nuvolari/features/settings/settings_screen.dart'; import 'package:nuvolari/features/sources/sources_screen.dart'; import 'package:nuvolari/l10n/app_localizations.dart'; /// Answers without touching the platform channels geolocator needs. class FakeLocationService implements LocationService { FakeLocationService(this.state); final LocationAvailability state; @override Future availability() async => state; @override Future request() async => state; @override Future currentPoint() async => const GeoPoint(7.686, 45.070); } Widget wrap( RegionConfig region, { LocationAvailability availability = LocationAvailability.denied, }) => ProviderScope( overrides: [ regionConfigProvider.overrideWith((ref) async => region), placesStoreProvider.overrideWithValue(InMemoryPlacesStore()), locationServiceProvider.overrideWithValue( FakeLocationService(availability), ), ], child: MaterialApp( locale: const Locale('it'), localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, home: const SettingsScreen(), ), ); void main() { late RegionConfig region; setUpAll(() { region = RegionConfig.parse( File('assets/regions/piemonte.json').readAsStringSync(), ); }); group('SettingsScreen', () { // The map carries no permanent credit line any more, so this entry is the // route the OSM attribution guidelines require. Losing it would be a // licence breach, not a cosmetic regression, so it is asserted here. testWidgets('offers the sources and licences entry', (tester) async { await tester.pumpWidget(wrap(region)); await tester.pumpAndSettle(); expect(find.text('Fonti e licenze'), findsOneWidget); expect( find.text('Licenze e attribuzioni dei dati mostrati'), findsOneWidget, ); }); testWidgets('opens the Sources screen from that entry', (tester) async { await tester.pumpWidget(wrap(region)); await tester.pumpAndSettle(); await tester.tap(find.text('Fonti e licenze')); await tester.pumpAndSettle(); expect(find.byType(SourcesScreen), findsOneWidget); expect(find.text('App non ufficiale'), findsOneWidget); }); // The disclosure has to be readable after the fact, not only in the moment // the system dialog is about to appear. testWidgets('repeats the location disclosure', (tester) async { await tester.pumpWidget(wrap(region)); await tester.pumpAndSettle(); expect(find.textContaining('resta sul dispositivo'), findsOneWidget); }); testWidgets('reports the permission state', (tester) async { await tester.pumpWidget( wrap(region, availability: LocationAvailability.granted), ); await tester.pumpAndSettle(); expect(find.text('Permesso concesso'), findsOneWidget); }); testWidgets('sends the user to system settings when refused for good', ( tester, ) async { await tester.pumpWidget( wrap(region, availability: LocationAvailability.deniedForever), ); await tester.pumpAndSettle(); expect(find.text('Apri impostazioni di sistema'), findsOneWidget); }); }); }