Files
Psychotoxical-psysonic/src/utils/componentHelpers/runArtistDetailPlay.test.ts
T
Maxim Isaev 1d65a8d339 fix(cluster): artist Play All/top tracks and member-scoped browse UX
Load artist album tracks via getAlbumForServer when clusterSeedServerId is set
so Play All, shuffle, and top-track clicks resolve on the correct member server.
Also improve connection indicator tooltips, Song Info server labels, artist browse
covers/detail fallbacks, and faster merged artist list SQL.
2026-06-05 18:38:10 +03:00

78 lines
3.1 KiB
TypeScript

import { describe, expect, it, vi, beforeEach } from 'vitest';
import type { SubsonicAlbum, SubsonicSong } from '../../api/subsonicTypes';
import {
buildArtistTopSongPlayQueue,
fetchArtistCatalogTracks,
} from './runArtistDetailPlay';
vi.mock('../../api/subsonicLibrary', () => ({
getAlbum: vi.fn(),
getAlbumForServer: vi.fn(),
}));
import { getAlbum, getAlbumForServer } from '../../api/subsonicLibrary';
const mockGetAlbum = vi.mocked(getAlbum);
const mockGetAlbumForServer = vi.mocked(getAlbumForServer);
describe('fetchArtistCatalogTracks', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('uses getAlbumForServer when clusterSeedServerId is set', async () => {
const albums: SubsonicAlbum[] = [
{ id: 'a1', name: 'Album', artist: 'A', artistId: 'ar1', songCount: 1, duration: 100, clusterSeedServerId: 'srv-1' },
];
mockGetAlbumForServer.mockResolvedValue({
album: { id: 'a1', name: 'Album', artist: 'A', artistId: 'ar1', songCount: 1, duration: 100, year: 2020 },
songs: [{ id: 't1', title: 'Track 1', artist: 'A', artistId: 'ar1', album: 'Album', albumId: 'a1', track: 1, duration: 100 }],
});
const tracks = await fetchArtistCatalogTracks(albums);
expect(mockGetAlbumForServer).toHaveBeenCalledWith('srv-1', 'a1');
expect(mockGetAlbum).not.toHaveBeenCalled();
expect(tracks).toHaveLength(1);
expect(tracks[0].id).toBe('t1');
expect(tracks[0].clusterBrowseServerId).toBe('srv-1');
});
it('uses getAlbum when no clusterSeedServerId', async () => {
const albums: SubsonicAlbum[] = [
{ id: 'a2', name: 'Album 2', artist: 'A', artistId: 'ar1', songCount: 1, duration: 100 },
];
mockGetAlbum.mockResolvedValue({
album: { id: 'a2', name: 'Album 2', artist: 'A', artistId: 'ar1', songCount: 1, duration: 100, year: 2019 },
songs: [{ id: 't2', title: 'Track 2', artist: 'A', artistId: 'ar1', album: 'Album 2', albumId: 'a2', track: 1, duration: 100 }],
});
const tracks = await fetchArtistCatalogTracks(albums);
expect(mockGetAlbum).toHaveBeenCalledWith('a2');
expect(mockGetAlbumForServer).not.toHaveBeenCalled();
expect(tracks[0].id).toBe('t2');
});
});
describe('buildArtistTopSongPlayQueue', () => {
const topSongs: SubsonicSong[] = [
{ id: 'top1', title: 'Top 1', artist: 'A', artistId: 'ar1', album: 'X', albumId: 'ax', duration: 100, clusterBrowseServerId: 's1' },
{ id: 'top2', title: 'Top 2', artist: 'A', artistId: 'ar1', album: 'Y', albumId: 'ay', duration: 100, clusterBrowseServerId: 's1' },
];
it('returns top songs from index when catalog is empty', () => {
const queue = buildArtistTopSongPlayQueue(topSongs, 1, []);
expect(queue.map(t => t.id)).toEqual(['top2']);
});
it('appends catalog tracks excluding top song ids', () => {
const catalog = [
{ id: 'top1', title: 'Top 1', artist: 'A', artistId: 'ar1', album: 'X', albumId: 'ax', duration: 100 },
{ id: 'other', title: 'Other', artist: 'A', artistId: 'ar1', album: 'Z', albumId: 'az', duration: 100 },
];
const queue = buildArtistTopSongPlayQueue(topSongs, 0, catalog);
expect(queue.map(t => t.id)).toEqual(['top1', 'top2', 'other']);
});
});