import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; import { render, screen } from '@testing-library/svelte'; import { readable } from 'svelte/store'; import { emptyLikesMock } from '../test-utils/mocks/likes'; import type { Playlist } from '$lib/api/types'; // Mock all the queries the home page constructs. vi.mock('$lib/api/home', () => ({ createHomeQuery: () => readable({ data: { recently_added_albums: [], most_played_tracks: [], rediscover_albums: [], rediscover_artists: [], last_played_artists: [] }, isPending: false, isError: false, refetch: vi.fn() }) })); vi.mock('$lib/api/playlists', () => ({ createPlaylistsQuery: vi.fn() })); vi.mock('$lib/api/me', () => ({ createSystemPlaylistsStatusQuery: vi.fn() })); // LikeButton imports — needed because the home renders cards that may use it. vi.mock('$lib/api/likes', () => emptyLikesMock()); import Page from './+page.svelte'; import { createPlaylistsQuery } from '$lib/api/playlists'; import { createSystemPlaylistsStatusQuery } from '$lib/api/me'; const emptyPlaylistsResponse = { owned: [], public: [] }; beforeEach(() => { (createPlaylistsQuery as unknown as ReturnType).mockImplementation(() => readable({ data: emptyPlaylistsResponse, isPending: false, isError: false }) ); (createSystemPlaylistsStatusQuery as unknown as ReturnType).mockReturnValue( readable({ data: { in_flight: false, last_run_at: null, last_error: null }, isPending: false, isError: false }) ); }); afterEach(() => vi.clearAllMocks()); describe('home Playlists section', () => { test('renders 5 placeholder cards when no playlists exist', () => { // Slot layout: For-You, Discover, 3× Songs-like. render(Page); const placeholders = screen.queryAllByTestId('playlist-placeholder-card'); expect(placeholders).toHaveLength(5); }); test('building status sets variant=building on placeholders', () => { (createSystemPlaylistsStatusQuery as unknown as ReturnType).mockReturnValue( readable({ data: { in_flight: true, last_run_at: null, last_error: null }, isPending: false, isError: false }) ); const { container } = render(Page); const buildingPlaceholders = container.querySelectorAll('[data-variant="building"]'); expect(buildingPlaceholders.length).toBeGreaterThan(0); }); test('renders For-You playlist + 3 placeholders when only for_you exists', () => { const forYou: Playlist = { id: 'fy', user_id: 'u1', owner_username: 'u1', name: 'For You', description: '', is_public: false, kind: 'system', system_variant: 'for_you', refreshable: false, seed_artist_id: null, cover_url: '', track_count: 25, duration_sec: 1500, created_at: '2026-05-04T00:00:00Z', updated_at: '2026-05-04T00:00:00Z' }; (createPlaylistsQuery as unknown as ReturnType).mockImplementation( (kind?: string) => kind === 'system' ? readable({ data: { owned: [forYou], public: [] }, isPending: false, isError: false }) : readable({ data: emptyPlaylistsResponse, isPending: false, isError: false }) ); render(Page); expect(screen.getByText('For You')).toBeInTheDocument(); const placeholders = screen.queryAllByTestId('playlist-placeholder-card'); // 1 Discover + 3 Songs-like slots = 4 placeholders alongside the // real For-You tile. expect(placeholders).toHaveLength(4); }); test('renders secondary system kinds (deep_cuts / new_for_you) after Songs-like slots', () => { // Operator backflow 2026-06-01: web Home surfaces the 5 secondary // system kinds when generated. No placeholders for them — they // depend on library shape, so missing means "not enough data." const makePlaylist = (id: string, variant: string, name: string): Playlist => ({ id, user_id: 'u1', owner_username: 'u1', name, description: '', is_public: false, kind: 'system', system_variant: variant, refreshable: variant !== 'songs_like_artist', seed_artist_id: null, cover_url: '', track_count: 25, duration_sec: 1500, created_at: '2026-05-04T00:00:00Z', updated_at: '2026-05-04T00:00:00Z' }); const owned = [ makePlaylist('fy', 'for_you', 'For You'), makePlaylist('dc', 'deep_cuts', 'Deep cuts'), makePlaylist('nfy', 'new_for_you', 'New for you') ]; (createPlaylistsQuery as unknown as ReturnType).mockImplementation( (kind?: string) => kind === 'system' ? readable({ data: { owned, public: [] }, isPending: false, isError: false }) : readable({ data: emptyPlaylistsResponse, isPending: false, isError: false }) ); render(Page); expect(screen.getByText('For You')).toBeInTheDocument(); expect(screen.getByText('Deep cuts')).toBeInTheDocument(); expect(screen.getByText('New for you')).toBeInTheDocument(); }); });