130 lines
3.9 KiB
Dart
130 lines
3.9 KiB
Dart
import 'package:drift/native.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:melo/library/database.dart';
|
|
import 'package:melo/downloads/server_titel_screen.dart';
|
|
import 'package:melo/player/audio_handler.dart';
|
|
import 'package:melo/services/download_service.dart';
|
|
import 'package:melo/services/navidrome_service.dart';
|
|
|
|
/// Merkt sich nur, was verlangt wurde — echte Downloads brauchen einen
|
|
/// Server, und darum geht es hier nicht.
|
|
class _FakeDownloads extends DownloadService {
|
|
_FakeDownloads(MeloDb db) : super(db: db, navidrome: NavidromeService());
|
|
|
|
final geladen = <String>[];
|
|
final entfernt = <String>[];
|
|
|
|
@override
|
|
bool get laeuft => false;
|
|
|
|
@override
|
|
Future<bool> ladeEinzelnenTitel(SubsonicSong song) async {
|
|
geladen.add(song.id);
|
|
return true;
|
|
}
|
|
|
|
@override
|
|
Future<bool> entferne(String navidromeId) async {
|
|
entfernt.add(navidromeId);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
final titel = [
|
|
const SubsonicSong(
|
|
id: 'nav-1',
|
|
titel: 'Nachtpuls',
|
|
kuenstler: 'Rotklang',
|
|
album: 'Nacht',
|
|
dauerSekunden: 200,
|
|
),
|
|
];
|
|
|
|
Future<({_FakeDownloads dienst, MeloAudioHandler handler})> pumpe(
|
|
WidgetTester tester,
|
|
{bool schonGeladen = false}) async {
|
|
final db = MeloDb(NativeDatabase.memory());
|
|
addTearDown(db.close);
|
|
if (schonGeladen) {
|
|
// Der Bildschirm liest den Zustand einmal per db.downloadIds().
|
|
await db.merkeDownload(DownloadsCompanion.insert(
|
|
navidromeId: 'nav-1',
|
|
titel: 'Nachtpuls',
|
|
groesseBytes: 1,
|
|
geladenAmMs: 0,
|
|
));
|
|
}
|
|
final dienst = _FakeDownloads(db);
|
|
// MeloAudioHandler startet einen periodischen Timer (Positions-
|
|
// Buchführung). Ohne handler.dispose() meldet der Testrahmen ihn als
|
|
// „pending" — dasselbe etablierte Muster wie in
|
|
// test/library/my_music_screen_test.dart: handler.dispose() explizit am
|
|
// Testende aufrufen (addTearDown greift zu spät, außerhalb der
|
|
// FakeAsync-Zone, in der der Timer geprüft wird).
|
|
final handler = MeloAudioHandler(db: db);
|
|
await tester.pumpWidget(
|
|
MultiProvider(
|
|
providers: [
|
|
Provider<MeloDb>.value(value: db),
|
|
ChangeNotifierProvider<DownloadService>.value(value: dienst),
|
|
Provider<MeloAudioHandler>.value(value: handler),
|
|
],
|
|
child: MaterialApp(
|
|
home: ServerTitelScreen(
|
|
titel: 'Nacht',
|
|
navidrome: NavidromeService(),
|
|
holeTitel: () async => titel,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle(
|
|
const Duration(milliseconds: 100),
|
|
EnginePhase.sendSemanticsUpdate,
|
|
const Duration(seconds: 5),
|
|
);
|
|
return (dienst: dienst, handler: handler);
|
|
}
|
|
|
|
testWidgets('ein einzelner Titel lässt sich offline nehmen', (tester) async {
|
|
final (:dienst, :handler) = await pumpe(tester);
|
|
|
|
await tester.tap(find.byTooltip('Offline nehmen'));
|
|
await tester.pumpAndSettle(
|
|
const Duration(milliseconds: 100),
|
|
EnginePhase.sendSemanticsUpdate,
|
|
const Duration(seconds: 5),
|
|
);
|
|
|
|
expect(dienst.geladen, ['nav-1']);
|
|
expect(dienst.entfernt, isEmpty);
|
|
|
|
handler.dispose();
|
|
});
|
|
|
|
testWidgets('ein schon geladener Titel bietet den Gegenweg an',
|
|
(tester) async {
|
|
final (:dienst, :handler) =
|
|
await pumpe(tester, schonGeladen: true);
|
|
|
|
// Zustand „schon offline": statt „Offline nehmen" steht dort das
|
|
// Entfernen — ohne diesen Test wäre der halbe Knopf ungeprüft.
|
|
expect(find.byTooltip('Offline nehmen'), findsNothing);
|
|
|
|
await tester.tap(find.byTooltip('Vom Gerät entfernen'));
|
|
await tester.pumpAndSettle(
|
|
const Duration(milliseconds: 100),
|
|
EnginePhase.sendSemanticsUpdate,
|
|
const Duration(seconds: 5),
|
|
);
|
|
|
|
expect(dienst.entfernt, ['nav-1']);
|
|
expect(dienst.geladen, isEmpty);
|
|
|
|
handler.dispose();
|
|
});
|
|
}
|