import 'package:cardash_launcher/core/theme/app_theme.dart'; import 'package:cardash_launcher/data/models/jellyfin_library.dart'; import 'package:cardash_launcher/data/models/jellyfin_models.dart'; import 'package:cardash_launcher/data/services/jellyfin_library_service.dart'; import 'package:cardash_launcher/features/jellyfin/jellyfin_dashboard_screen.dart'; import 'package:cardash_launcher/features/jellyfin/jellyfin_playback_controller.dart'; import 'package:cardash_launcher/features/settings/jellyfin_controller.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:provider/provider.dart'; import 'jellyfin_fakes.dart'; class _Fixture { _Fixture({ required this.jellyfin, required this.gateway, required this.library, required this.playback, }); final JellyfinController jellyfin; final FakeJellyfinLibraryGateway gateway; final JellyfinLibraryService library; final JellyfinPlaybackController playback; } Future<_Fixture> _fixture({List genres = const ['metal']}) async { final jellyfin = await configuredJellyfinController(); await jellyfin.setGenreSelections([ for (final id in genres) JellyfinGenreSelection(id: id, label: id), ]); final gateway = FakeJellyfinLibraryGateway() ..played = [ track('a2', albumId: 'album-a', albumName: 'Album A'), track('a1', albumId: 'album-a', albumName: 'Album A'), track('b1', albumId: 'album-b', albumName: 'Album B'), track('c1', albumId: 'album-c', albumName: 'Album C'), track('d1', albumId: 'album-d', albumName: 'Album D'), track('e1', albumId: 'album-e', albumName: 'Album E'), track('f1', albumId: 'album-f', albumName: 'Album F'), ] ..added = [ album('new-1'), album('new-2'), album('new-3'), album('new-4'), album('new-5'), album('new-6'), ] ..random = [ album('r1'), album('r2'), album('r3'), album('r4'), album('r5'), album('r6'), ] ..genres = const ['Metal', 'Jazz']; final library = testLibraryService(jellyfin, gateway); final playback = JellyfinPlaybackController( FakeJellyfinPlaybackPlatform(), library, jellyfin, pollInterval: const Duration(hours: 1), ); return _Fixture( jellyfin: jellyfin, gateway: gateway, library: library, playback: playback, ); } Future _pump(WidgetTester tester, _Fixture fixture) async { await tester.binding.setSurfaceSize(const Size(1280, 800)); addTearDown(() => tester.binding.setSurfaceSize(null)); addTearDown(fixture.playback.dispose); addTearDown(fixture.jellyfin.dispose); await tester.pumpWidget( MultiProvider( providers: [ Provider.value(value: fixture.library), ChangeNotifierProvider.value( value: fixture.jellyfin, ), ChangeNotifierProvider.value( value: fixture.playback, ), ], child: MaterialApp( theme: AppTheme.light(), home: const JellyfinDashboardScreen(), ), ), ); await tester.pumpAndSettle(); } void main() { testWidgets('renders six cards per row on a wide screen', (tester) async { final fixture = await _fixture(); await _pump(tester, fixture); expect(find.text('Recently played'), findsOneWidget); expect(find.text('Recently added'), findsOneWidget); expect(find.text('Random'), findsOneWidget); expect(find.text('Artists'), findsOneWidget); expect(find.text('Album A'), findsWidgets); expect(find.text('Album F'), findsOneWidget); expect(find.text('Album new-1'), findsOneWidget); expect(find.text('Album new-6'), findsOneWidget); expect(find.text('Album r1'), findsOneWidget); expect(find.text('Album r6'), findsOneWidget); expect(find.bySemanticsLabel('Shuffle random albums'), findsOneWidget); expect(tester.takeException(), isNull); }); testWidgets('shows the genre prompt when no genres are selected', ( tester, ) async { final fixture = await _fixture(genres: const []); await _pump(tester, fixture); expect(find.text('Choose up to 5 genres in Settings.'), findsOneWidget); expect(find.bySemanticsLabel('Shuffle random albums'), findsNothing); expect(fixture.gateway.randomCalls, 0); }); testWidgets('shows an inline error with retry when the server fails', ( tester, ) async { final fixture = await _fixture(); fixture.gateway.error = JellyfinUnreachable('offline'); await _pump(tester, fixture); expect( find.text('Jellyfin is unreachable. Check the server and try again.'), findsOneWidget, ); expect(find.text('Retry'), findsOneWidget); expect(find.bySemanticsLabel('Shuffle random albums'), findsNothing); }); }