import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:minstrel/api/endpoints/playlists.dart'; import 'package:minstrel/library/home_screen.dart'; import 'package:minstrel/library/library_providers.dart'; import 'package:minstrel/models/home_index.dart'; import 'package:minstrel/models/playlist.dart'; import 'package:minstrel/models/system_playlists_status.dart'; import 'package:minstrel/playlists/playlists_provider.dart'; import 'package:minstrel/theme/theme_data.dart'; // All tests pump an empty HomeIndex unless they care about populated // section IDs — per-tile hydration is intentionally not exercised here. // What this suite verifies is the screen's section-level shape: // placeholders / empty-state copy / section presence given the index. const _emptyIndex = HomeIndex.empty; void main() { testWidgets('renders 4 placeholder cards in Playlists row when no system playlists exist', (tester) async { await tester.pumpWidget(ProviderScope( overrides: [ homeIndexProvider.overrideWith((ref) => Stream.value(_emptyIndex)), playlistsListProvider('all').overrideWith( (ref) => Stream.value(PlaylistsList.empty()), ), systemPlaylistsStatusProvider.overrideWith( (ref) => Stream.value(SystemPlaylistsStatus.empty()), ), ], child: MaterialApp(theme: buildThemeData(), home: const HomeScreen()), )); await tester.pumpAndSettle(); // For-You placeholder + Discover placeholder + 3 Songs-like placeholders. expect(find.text('For You'), findsOneWidget); expect(find.text('Discover'), findsOneWidget); expect(find.text('Songs like…'), findsNWidgets(3)); }); testWidgets('renders empty-state copy for each section when the index is empty', (tester) async { await tester.pumpWidget(ProviderScope( overrides: [ homeIndexProvider.overrideWith((ref) => Stream.value(_emptyIndex)), playlistsListProvider('all').overrideWith( (ref) => Stream.value(PlaylistsList.empty()), ), systemPlaylistsStatusProvider.overrideWith( (ref) => Stream.value(SystemPlaylistsStatus.empty()), ), ], child: MaterialApp(theme: buildThemeData(), home: const HomeScreen()), )); await tester.pumpAndSettle(); expect( find.text("Nothing added yet. Scan a folder via the server's config."), findsOneWidget, ); expect( find.text('No forgotten favourites yet. Like some albums or artists to fill this in.'), findsOneWidget, ); expect(find.text('No plays to draw from. Listen to something.'), findsOneWidget); expect(find.text('No recent plays.'), findsOneWidget); }); testWidgets('renders For-You card when system playlist exists', (tester) async { const forYou = Playlist( id: 'fy', userId: 'u1', name: 'For You', description: '', isPublic: false, systemVariant: 'for_you', trackCount: 75, coverUrl: '', ownerUsername: 'alice', createdAt: '2026-05-01T00:00:00Z', updatedAt: '2026-05-01T00:00:00Z', ); await tester.pumpWidget(ProviderScope( overrides: [ homeIndexProvider.overrideWith((ref) => Stream.value(_emptyIndex)), playlistsListProvider('all').overrideWith( (ref) => Stream.value( const PlaylistsList(owned: [forYou], public: [])), ), systemPlaylistsStatusProvider.overrideWith( (ref) => Stream.value(SystemPlaylistsStatus.empty()), ), ], child: MaterialApp(theme: buildThemeData(), home: const HomeScreen()), )); await tester.pumpAndSettle(); // The real card carries the playlist name + the "for you" badge. expect(find.text('For You'), findsOneWidget); expect(find.text('for you'), findsOneWidget); }); // Section-with-populated-IDs coverage lives in the drift-tagged // integration suite (Slice F follow-up) because per-tile providers // require a real (in-memory) drift DB. The flutter-ci runner skips // drift tests pending libsqlite3. }