import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:plezy/i18n/strings.g.dart'; import 'package:plezy/media/media_backend.dart'; import 'package:plezy/media/media_item.dart'; import 'package:plezy/media/media_kind.dart'; import 'package:plezy/providers/multi_server_provider.dart'; import 'package:plezy/screens/music/queue_sheet.dart'; import 'package:plezy/services/data_aggregation_service.dart'; import 'package:plezy/services/multi_server_manager.dart'; import 'package:plezy/services/music/music_playback_service.dart'; import 'package:plezy/services/settings_service.dart'; import 'package:plezy/theme/mono_theme.dart'; import 'package:plezy/widgets/music/track_row.dart'; import 'package:provider/provider.dart'; import '../../test_helpers/prefs.dart'; MediaItem _track(String id, String title) => MediaItem( id: id, backend: MediaBackend.plex, kind: MediaKind.track, title: title, parentId: 'album_1', parentTitle: 'First Light', grandparentId: 'artist_1', grandparentTitle: 'Test Artist', durationMs: 180000, serverId: 'server_1', serverName: 'Server', ); /// Fixed-state fake queue: three tracks, playing the first. class _FakeQueueService extends StubMusicPlaybackService { final List tracks; final List jumps = []; _FakeQueueService(this.tracks); @override bool get isAvailable => true; @override MediaItem? get currentTrack => tracks.first; @override MusicPlaybackStatus get status => MusicPlaybackStatus.playing; @override List get queue => tracks; @override int get currentIndex => 0; @override Future jumpTo(int index) async { jumps.add(index); } } void main() { TestWidgetsFlutterBinding.ensureInitialized(); setUp(() async { resetSharedPreferencesForTest(); SettingsService.resetForTesting(); LocaleSettings.setLocaleSync(AppLocale.en); await SettingsService.getInstance(); }); Widget wrap(MusicPlaybackService service) { final manager = MultiServerManager(); final multiServerProvider = MultiServerProvider(manager, DataAggregationService(manager)); addTearDown(multiServerProvider.dispose); return TranslationProvider( child: MultiProvider( providers: [ ChangeNotifierProvider.value(value: multiServerProvider), ChangeNotifierProvider.value(value: service), ], child: MaterialApp( theme: monoTheme(dark: true), home: const Scaffold(body: SizedBox(width: 500, height: 700, child: QueueSheet())), ), ), ); } testWidgets('renders header, pinned current track, and upcoming rows', (tester) async { final service = _FakeQueueService([_track('t1', 'Alpha'), _track('t2', 'Beta'), _track('t3', 'Gamma')]); await tester.pumpWidget(wrap(service)); // pumpAndSettle would never settle: the current-track equalizer animates // forever while the fake reports "playing". await tester.pump(); await tester.pump(const Duration(milliseconds: 300)); // Header: title + total track count. expect(find.text(t.music.queue), findsOneWidget); expect(find.text(t.music.trackCount(n: 3)), findsOneWidget); // Pinned current row (not a TrackRow) + "Up next" label. expect(find.text('Alpha'), findsOneWidget); expect(find.text(t.music.upNext), findsOneWidget); // Upcoming tracks render as TrackRows. expect(find.byType(TrackRow), findsNWidgets(2)); expect(find.text('Beta'), findsOneWidget); expect(find.text('Gamma'), findsOneWidget); }); testWidgets('tapping an upcoming row jumps to its queue index', (tester) async { final service = _FakeQueueService([_track('t1', 'Alpha'), _track('t2', 'Beta'), _track('t3', 'Gamma')]); await tester.pumpWidget(wrap(service)); // pumpAndSettle would never settle: the current-track equalizer animates // forever while the fake reports "playing". await tester.pump(); await tester.pump(const Duration(milliseconds: 300)); await tester.tap(find.text('Gamma')); await tester.pump(); expect(service.jumps, [2]); }); }