import 'package:drift/drift.dart' show Value, driftRuntimeOptions; import 'package:drift/native.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:melo/library/category_service.dart'; import 'package:melo/library/database.dart'; import 'package:melo/library/playlist_service.dart'; import 'package:melo/settings/app_settings.dart'; import 'package:melo/shared/sort_store.dart'; import 'package:melo/shared/sortable_song_list.dart'; /// Langes Drücken schaltet in die Mehrfachauswahl. Geprüft wird, dass dabei /// nichts abspielt und die Kopfzeile wechselt. /// /// **Aufbau bewusst im Testkörper, nicht in `setUp`.** `setUp` läuft außerhalb /// der Testzone: Datenbank und Dienste entstünden dort in echter Zeit, /// während `pumpAndSettle` in Testzeit auf ihre Ströme wartet — der Test hängt /// dann endlos. Dieselbe Klasse Hänger beschreibt BACKLOG.md. void main() { final lieder = [ for (var i = 0; i < 3; i++) Song( id: 'song-$i', path: '/music/$i.mp3', title: 'Titel $i', artist: 'Neoni', dateAddedMs: i, updatedAtMs: 0, deleted: false, playCount: 0, categoriesEdited: false, metadataEdited: false, ), ]; /// Begrenzt statt unbegrenzt: hängt doch einmal etwas, scheitert der Test /// in Sekunden, statt den ganzen Lauf zu blockieren. Future beruhige(WidgetTester tester) => tester.pumpAndSettle( const Duration(milliseconds: 100), EnginePhase.sendSemanticsUpdate, const Duration(seconds: 5), ); Future pumpe(WidgetTester tester) async { driftRuntimeOptions.dontWarnAboutMultipleDatabases = true; SharedPreferences.setMockInitialValues({}); final db = MeloDb(NativeDatabase.memory()); final einstellungen = AppSettings(); await einstellungen.init(); for (final song in lieder) { await db.into(db.songs).insert(SongsCompanion.insert( id: song.id, path: song.path, title: song.title, artist: Value(song.artist), dateAddedMs: song.dateAddedMs, updatedAtMs: 0, )); } await tester.pumpWidget( MultiProvider( providers: [ Provider.value(value: db), ChangeNotifierProvider.value( value: CategoryService(db)), ChangeNotifierProvider.value( value: PlaylistService(db)), ChangeNotifierProvider.value(value: einstellungen), ], child: MaterialApp( home: Scaffold( body: SortableSongList( songs: lieder, storeKey: SortStore.meineMusik, ), ), ), ), ); await beruhige(tester); } Future aufraeumen(WidgetTester tester) async { // Kein db.close(): drift plant dabei eine Aufräum-Aufgabe ein, die der // Testrahmen nicht mehr abarbeitet (siehe BACKLOG.md). await tester.pumpWidget(const SizedBox()); await tester.pump(const Duration(milliseconds: 1)); } testWidgets('ohne Auswahl steht die Shuffle-Zeile da', (tester) async { await pumpe(tester); expect(find.text('Shuffle-Wiedergabe'), findsOneWidget); expect(find.text('1 Titel ausgewählt'), findsNothing); await aufraeumen(tester); }); testWidgets('langes Drücken beginnt die Auswahl', (tester) async { await pumpe(tester); await tester.longPress(find.text('Titel 0')); await beruhige(tester); expect(find.text('1 Titel ausgewählt'), findsOneWidget); // Die Shuffle-Zeile weicht, statt darüber zu wachsen — sonst rutschte // die Liste beim Auswählen nach unten weg. expect(find.text('Shuffle-Wiedergabe'), findsNothing); await aufraeumen(tester); }); testWidgets('im Auswahl-Modus wählt ein Tipp aus, statt abzuspielen', (tester) async { await pumpe(tester); await tester.longPress(find.text('Titel 0')); await beruhige(tester); await tester.tap(find.text('Titel 1')); await beruhige(tester); expect(find.text('2 ausgewählt'), findsOneWidget); await aufraeumen(tester); }); testWidgets('den letzten abwählen beendet die Auswahl', (tester) async { await pumpe(tester); await tester.longPress(find.text('Titel 0')); await beruhige(tester); await tester.tap(find.text('Titel 0')); await beruhige(tester); expect(find.text('Shuffle-Wiedergabe'), findsOneWidget); await aufraeumen(tester); }); testWidgets('das Kreuz beendet die Auswahl', (tester) async { await pumpe(tester); await tester.longPress(find.text('Titel 0')); await beruhige(tester); await tester.tap(find.byTooltip('Auswahl beenden')); await beruhige(tester); expect(find.text('Shuffle-Wiedergabe'), findsOneWidget); await aufraeumen(tester); }); }