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/region_config.dart'; import 'package:nuvolari/core/region/region_repository.dart'; import 'package:nuvolari/features/sources/sources_screen.dart'; import 'package:nuvolari/l10n/app_localizations.dart'; RegionConfig loadPiemonte() => RegionConfig.parse(File('assets/regions/piemonte.json').readAsStringSync()); Widget wrap(Widget child, RegionConfig region) => ProviderScope( overrides: [regionConfigProvider.overrideWith((ref) async => region)], child: MaterialApp( locale: const Locale('it'), localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, home: child, ), ); void main() { late RegionConfig region; setUpAll(() { region = loadPiemonte(); }); group('SourcesScreen', () { testWidgets('lists every configured source with its licence', ( tester, ) async { await tester.pumpWidget(wrap(const SourcesScreen(), region)); await tester.pumpAndSettle(); // The list is longer than the test viewport, so each entry is scrolled to // rather than expected to be on screen at once. Asserting only on what // happens to fit would let a credit fall off the bottom unnoticed. for (final attribution in region.attributions) { await tester.scrollUntilVisible( find.text(attribution.text), 200, scrollable: find.byType(Scrollable).first, ); await tester.pumpAndSettle(); expect( find.text(attribution.text), findsOneWidget, reason: '${attribution.id} is missing from the Sources screen', ); // Assert the licence while its row is on screen. Checking at the end // would only prove whatever the last scroll happened to leave visible. final license = attribution.license; expect( find.text( license == null ? 'Nessuna licenza dichiarata dalla fonte' : 'Licenza: $license', ), findsWidgets, reason: 'the licence for ${attribution.id} is not shown beside it', ); } }); // ARPA publishes no licence for the alert bulletin. Showing an invented one // would be worse than showing none, so the screen must say so explicitly. testWidgets('says when a source states no licence', (tester) async { await tester.pumpWidget(wrap(const SourcesScreen(), region)); await tester.pumpAndSettle(); expect(find.text('Nessuna licenza dichiarata dalla fonte'), findsWidgets); }); testWidgets('shows the independence disclaimer', (tester) async { await tester.pumpWidget(wrap(const SourcesScreen(), region)); await tester.pumpAndSettle(); expect(find.text('App non ufficiale'), findsOneWidget); expect(find.textContaining('indipendente'), findsOneWidget); }); testWidgets('explains the share-alike obligation', (tester) async { await tester.pumpWidget(wrap(const SourcesScreen(), region)); await tester.pumpAndSettle(); // Below the fold in the test viewport once the base-map credits are listed. await tester.scrollUntilVisible( find.text('Dati derivati'), 200, scrollable: find.byType(Scrollable).first, ); await tester.pumpAndSettle(); expect(find.text('Dati derivati'), findsOneWidget); expect(find.textContaining('CC BY-SA'), findsWidgets); }); testWidgets('links the official bulletin', (tester) async { await tester.pumpWidget(wrap(const SourcesScreen(), region)); await tester.pumpAndSettle(); // The button sits below the fold in the test viewport. await tester.scrollUntilVisible( find.text('Bollettino ufficiale Arpa Piemonte'), 200, scrollable: find.byType(Scrollable).first, ); await tester.pumpAndSettle(); expect(find.text('Bollettino ufficiale Arpa Piemonte'), findsOneWidget); }); }); }