Files
minstrel/web/src/routes/page.test.ts
T
bvandeusen d43719516e
test-web / test (push) Successful in 33s
feat(web): drop hero row + compact Rediscover tiles
Operator UI review on the merged build:

- Hero row felt 'odd' — operator chose remove-entirely on the
  AskUserQuestion options. The Playlists row already leads with
  For-You and Recently Added leads with the newest album, so the
  hero duplicated both anchors. Pulled HomeHeroCard.svelte + all
  page-level wiring (systemShuffle/getPlaylist imports + playForYou/
  playLatestAlbum handlers) and reverted the within() test scoping
  added in 682d7a5e.

- Rediscover tiles step down to w-32 (albums) / w-28 (artists),
  matching the Most Played CompactTrackCard visual weight on web.
  Reinforces the page hierarchy: fresh content gets real estate,
  throwbacks recede.
2026-06-01 20:34:21 -04:00

151 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<typeof vi.fn>).mockImplementation(() =>
readable({ data: emptyPlaylistsResponse, isPending: false, isError: false })
);
(createSystemPlaylistsStatusQuery as unknown as ReturnType<typeof vi.fn>).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<typeof vi.fn>).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<typeof vi.fn>).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<typeof vi.fn>).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();
});
});