feat(web/playlists): Discover refresh button (detail + home kebab)
Operator can refresh their Discover playlist without waiting for the next daily cron tick. Two surfaces, both gated on system_variant === 'discover': - Detail page header: "Refresh" button next to the cover art / meta. - Home Playlists row tile kebab: "Refresh Discover" menu item. Both call POST /api/playlists/system/discover/refresh, show a confirmation toast, and invalidate the playlist + playlists queries so the new content lands without a manual page reload. Extends Playlist.system_variant union with 'discover'. Adds refreshDiscover() typed client. Tests cover client behaviour (success + empty-library) plus conditional rendering on both surfaces.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { refreshDiscover } from './playlists';
|
||||
|
||||
vi.mock('./client', () => ({
|
||||
apiFetch: vi.fn()
|
||||
}));
|
||||
|
||||
import { apiFetch } from './client';
|
||||
|
||||
describe('refreshDiscover', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('POSTs the correct path and returns the response', async () => {
|
||||
const sample = { playlist_id: 'abc-123', track_count: 100 };
|
||||
(apiFetch as unknown as ReturnType<typeof vi.fn>).mockResolvedValueOnce(sample);
|
||||
const got = await refreshDiscover();
|
||||
expect(apiFetch).toHaveBeenCalledWith(
|
||||
'/api/playlists/system/discover/refresh',
|
||||
expect.objectContaining({ method: 'POST' })
|
||||
);
|
||||
expect(got).toEqual(sample);
|
||||
});
|
||||
|
||||
it('handles empty-library response', async () => {
|
||||
const sample = { playlist_id: null, track_count: 0 };
|
||||
(apiFetch as unknown as ReturnType<typeof vi.fn>).mockResolvedValueOnce(sample);
|
||||
const got = await refreshDiscover();
|
||||
expect(got.playlist_id).toBe(null);
|
||||
expect(got.track_count).toBe(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user