import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; import 'package:http/testing.dart'; import 'package:melo/downloads/downloads_screen.dart'; import 'package:melo/services/baka_auth.dart'; import 'package:melo/services/yt_download_service.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; class _MemorySpeicher implements TokenSpeicher { final Map werte = {}; @override Future lesen(String key) async => werte[key]; @override Future schreiben(String key, String wert) async => werte[key] = wert; @override Future loeschen(String key) async => werte.remove(key); } Widget _wrap(BakaAuth auth) { return MultiProvider( providers: [ ChangeNotifierProvider.value(value: auth), ChangeNotifierProvider( create: (_) => YtDownloadService( auth: auth, client: MockClient((_) async => http.Response('', 500)), ), ), ], child: const MaterialApp(home: Scaffold(body: DownloadsScreen())), ); } Future _angemeldet() async { final auth = BakaAuth( client: MockClient((_) async => http.Response(jsonEncode({'token': 'jwt'}), 200)), speicher: _MemorySpeicher(), ); await auth.anmelden('Baka', 'geheim'); return auth; } void main() { TestWidgetsFlutterBinding.ensureInitialized(); const medienKanal = MethodChannel('de.baka.melo/media_store'); final messenger = TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger; /// Ein Handy ohne SD-Karte — mehr Speicherorte setzt der jeweilige Test. void nurInternerSpeicher() { messenger.setMockMethodCallHandler(medienKanal, (call) async { if (call.method != 'listVolumes') return null; return [ {'name': 'external_primary', 'beschreibung': 'Interner Speicher'}, ]; }); } setUp(() { SharedPreferences.setMockInitialValues({}); nurInternerSpeicher(); }); tearDown(() => messenger.setMockMethodCallHandler(medienKanal, null)); testWidgets('Online-Tab hat die Unterreiter YouTube und Server', (tester) async { final auth = BakaAuth(client: MockClient((_) async => http.Response('', 500)), speicher: _MemorySpeicher()); await tester.pumpWidget(_wrap(auth)); await tester.pump(); expect(find.text('YouTube'), findsOneWidget); expect(find.text('Server'), findsOneWidget); }); testWidgets('Ohne Anmeldung fordert der YouTube-Bereich zum Anmelden auf', (tester) async { final auth = BakaAuth(client: MockClient((_) async => http.Response('', 500)), speicher: _MemorySpeicher()); await tester.pumpWidget(_wrap(auth)); await tester.pump(); expect(find.text('Beim Baka-Konto anmelden'), findsOneWidget); expect(find.byType(TextField), findsNothing); }); testWidgets('Angemeldet zeigt der YouTube-Bereich das Adressfeld', (tester) async { final auth = BakaAuth( client: MockClient( (_) async => http.Response(jsonEncode({'token': 'jwt'}), 200)), speicher: _MemorySpeicher(), ); await auth.anmelden('Baka', 'geheim'); await tester.pumpWidget(_wrap(auth)); await tester.pump(); expect(find.text('Angemeldet als Baka'), findsOneWidget); expect(find.byType(TextField), findsOneWidget); expect(find.text('Herunterladen'), findsOneWidget); }); testWidgets('Der Cookie-Schalter steht anfangs an', (tester) async { await tester.pumpWidget(_wrap(await _angemeldet())); await tester.pumpAndSettle(); expect(find.text('YouTube-Cookies des Servers verwenden'), findsOneWidget); expect(tester.widget(find.byType(SwitchListTile)).value, isTrue); }); testWidgets('Abschalten des Cookie-Schalters wird gemerkt', (tester) async { await tester.pumpWidget(_wrap(await _angemeldet())); await tester.pumpAndSettle(); await tester.tap(find.byType(SwitchListTile)); await tester.pumpAndSettle(); expect(tester.widget(find.byType(SwitchListTile)).value, isFalse); final prefs = await SharedPreferences.getInstance(); expect(prefs.getBool('yt_cookies'), isFalse); }); testWidgets('Gemerktes Abschalten gilt auch nach dem Neustart', (tester) async { SharedPreferences.setMockInitialValues({'yt_cookies': false}); await tester.pumpWidget(_wrap(await _angemeldet())); await tester.pumpAndSettle(); expect(tester.widget(find.byType(SwitchListTile)).value, isFalse); }); testWidgets('Mehrere Speicherorte bringen die Auswahl zum Vorschein', (tester) async { messenger.setMockMethodCallHandler(medienKanal, (call) async { if (call.method != 'listVolumes') return null; return [ {'name': 'external_primary', 'beschreibung': 'Interner Speicher'}, {'name': '1234-abcd', 'beschreibung': 'SD-Karte (1234-abcd)'}, ]; }); await tester.pumpWidget(_wrap(await _angemeldet())); await tester.pumpAndSettle(); expect(find.byType(DropdownButtonFormField), findsOneWidget); expect(find.text('Speicherort'), findsOneWidget); }); testWidgets('Bei nur einem Speicherort gibt es keine Auswahl', (tester) async { await tester.pumpWidget(_wrap(await _angemeldet())); await tester.pumpAndSettle(); expect(find.byType(DropdownButtonFormField), findsNothing); }); }