import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:melo_app/models/song.dart'; import 'package:melo_app/screens/login_screen.dart'; import 'package:melo_app/screens/home_screen.dart'; import 'package:melo_app/services/player_service.dart'; import 'package:melo_app/utils/farb_theme.dart'; import 'package:melo_app/widgets/warteschlange_sheet.dart'; import 'package:melo_app/widgets/press_scale.dart'; Song _song(int id, String titel) => Song( id: id, titel: titel, kuenstler: 'Künstler $id', dauerSekunden: 100, dateiPfad: '', ); void main() { setUp(() { // PlayerService ist ein Singleton — Zustand vor jedem Test zurücksetzen final p = PlayerService(); p.setZufallsmodus(false); p.setWiederholmodus(Wiederholmodus.aus); p.cancelSleepTimer(); p.setWarteschlange([]); }); testWidgets('LoginScreen zeigt Anmelde-Felder', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: LoginScreen())); await tester.pumpAndSettle(); // Prüft dass was gerendert wird (kein Crash) expect(find.byType(TextField), findsWidgets); }); testWidgets('WarteschlangeSheet zeigt echte Wiedergabe-Reihenfolge', (WidgetTester tester) async { final p = PlayerService(); p.setWarteschlange( [_song(1, 'Aktuell'), _song(2, 'Naechster'), _song(3, 'Danach')], startIndex: 1); await tester.pumpWidget( const MaterialApp(home: Scaffold(body: WarteschlangeSheet()))); await tester.pump(); // Aktueller Song oben, deutlich markiert (▶ + „Jetzt spielt"-Chip) expect(find.text('Jetzt spielt'), findsOneWidget); expect(find.byIcon(Icons.play_arrow), findsOneWidget); // Echte Reihenfolge: aktueller Song zuerst, dann die nächsten Lieder expect(find.text('Naechster'), findsOneWidget); expect(find.text('Danach'), findsOneWidget); // Kopfzeile zählt die Wiedergabe-Reihenfolge (nicht die Bibliothek) expect(find.text('2 Titel'), findsOneWidget); }); testWidgets('WarteschlangeSheet zeigt Wiederholung-Hinweis bei Repeat', (WidgetTester tester) async { final p = PlayerService(); p.setWarteschlange([_song(1, 'A'), _song(2, 'B'), _song(3, 'C')]); p.setWiederholmodus(Wiederholmodus.playlist); await tester.pumpWidget( const MaterialApp(home: Scaffold(body: WarteschlangeSheet()))); await tester.pump(); expect(find.textContaining('Wiederholung aktiv'), findsOneWidget); }); // ═══ NEUE TESTS v2.56: Melo Dark Fusion ═══ testWidgets('ThemeExtension: MeloDesignTokens liefert korrekte Werte', (WidgetTester tester) async { // Theme bauen und Extension prüfen final theme = MeloTheme.themeMitAkzent(const Color(0xFFCC0000)); final tokens = theme.extensions[MeloDesignTokens] as MeloDesignTokens?; expect(tokens, isNotNull); expect(tokens!.hintergrund, const Color(0xFF0B0B10)); expect(tokens.oberflaeche, const Color(0xFF14141C)); expect(tokens.karte, const Color(0xFF1C1C26)); expect(tokens.textPrimaer, const Color(0xFFF5F5F7)); expect(tokens.textSekundaer, const Color(0xFF9E9EAB)); expect(tokens.erfolg, const Color(0xFF4CAF50)); expect(tokens.warnung, const Color(0xFFFF9800)); expect(tokens.fehler, const Color(0xFFF44336)); expect(tokens.cardRadius, 20); expect(tokens.buttonRadius, 999); expect(tokens.sheetRadius, 28); expect(tokens.dialogRadius, 24); expect(tokens.inputRadius, 14); }); testWidgets('Expertenmodus-Toggle: SharedPreferences Key existiert', (WidgetTester tester) async { // SharedPreferences mock: experten_modus = true setzen und prüfen SharedPreferences.setMockInitialValues({'experten_modus': true}); final prefs = await SharedPreferences.getInstance(); final experte = prefs.getBool('experten_modus') ?? false; expect(experte, isTrue); // Zurücksetzen await prefs.setBool('experten_modus', false); final experte2 = prefs.getBool('experten_modus') ?? false; expect(experte2, isFalse); }); testWidgets('Akzentfarbe bleibt anwendbar (MeloTheme.akzentNotifier)', (WidgetTester tester) async { // Ursprüngliche Akzentfarbe merken final original = MeloTheme.akzent; // Neue Farbe setzen MeloTheme.akzent = const Color(0xFF2E9E4F); // Grün expect(MeloTheme.akzent, const Color(0xFF2E9E4F)); // Theme spiegelt die Änderung wider final theme = MeloTheme.theme; expect(theme.colorScheme.primary, const Color(0xFF2E9E4F)); // Wieder zurücksetzen MeloTheme.akzent = original; }); testWidgets('PressScale-Widget existiert und reagiert auf Tap', (WidgetTester tester) async { bool wurdeGetapt = false; await tester.pumpWidget( MaterialApp( home: Scaffold( body: Center( child: PressScale( onTap: () => wurdeGetapt = true, child: Container( width: 48, height: 48, decoration: const BoxDecoration( shape: BoxShape.circle, color: Colors.red, ), child: const Icon(Icons.play_arrow, color: Colors.white), ), ), ), ), ), ); await tester.pump(); // Widget existiert expect(find.byIcon(Icons.play_arrow), findsOneWidget); // Tippen await tester.tap(find.byIcon(Icons.play_arrow)); await tester.pump(); expect(wurdeGetapt, isTrue); }); testWidgets('Startseiten-Hero zeigt Song-Titel an (weiterhoeren_titel)', (WidgetTester tester) async { // Einen laufenden Song setzen final p = PlayerService(); final testSong = _song(1, 'Test Hero Song'); p.setWarteschlange([testSong]); await tester.pumpWidget( const MaterialApp(home: Scaffold(body: MeloHome())), ); await tester.pump(); // Der Hero-Bereich sollte den Song-Titel anzeigen // (kann leer sein wenn ViewModel noch lädt, aber Widget existiert) // Prüfe nur dass die App ohne Crash rendert expect(find.byType(MeloHome), findsOneWidget); }); }