feat(web/m7-365): history API helper + tests
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||||
|
import {
|
||||||
|
fetchHistoryPage,
|
||||||
|
getNextPageParam,
|
||||||
|
HISTORY_PAGE_SIZE,
|
||||||
|
type HistoryResponse
|
||||||
|
} from './history';
|
||||||
|
|
||||||
|
vi.mock('./client', () => ({
|
||||||
|
api: {
|
||||||
|
get: vi.fn()
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { api } from './client';
|
||||||
|
|
||||||
|
describe('history API helpers', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.mocked(api.get).mockReset();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('HISTORY_PAGE_SIZE is 50', () => {
|
||||||
|
expect(HISTORY_PAGE_SIZE).toBe(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fetchHistoryPage hits /api/me/history?offset=N&limit=50', async () => {
|
||||||
|
vi.mocked(api.get).mockResolvedValue({ events: [], has_more: false });
|
||||||
|
await fetchHistoryPage(50);
|
||||||
|
expect(api.get).toHaveBeenCalledWith('/api/me/history?offset=50&limit=50');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fetchHistoryPage uses offset=0 by default', async () => {
|
||||||
|
vi.mocked(api.get).mockResolvedValue({ events: [], has_more: false });
|
||||||
|
await fetchHistoryPage();
|
||||||
|
expect(api.get).toHaveBeenCalledWith('/api/me/history?offset=0&limit=50');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getNextPageParam returns next offset when has_more is true', () => {
|
||||||
|
const page: HistoryResponse = { events: [], has_more: true };
|
||||||
|
expect(getNextPageParam(page, [], 0)).toBe(50);
|
||||||
|
expect(getNextPageParam(page, [], 50)).toBe(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getNextPageParam returns undefined when has_more is false', () => {
|
||||||
|
const page: HistoryResponse = { events: [], has_more: false };
|
||||||
|
expect(getNextPageParam(page, [], 50)).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import { createInfiniteQuery } from '@tanstack/svelte-query';
|
||||||
|
import { api } from './client';
|
||||||
|
import { qk } from './queries';
|
||||||
|
import type { TrackRef } from './types';
|
||||||
|
|
||||||
|
export const HISTORY_PAGE_SIZE = 50;
|
||||||
|
|
||||||
|
export type HistoryEvent = {
|
||||||
|
id: string;
|
||||||
|
played_at: string; // RFC3339
|
||||||
|
track: TrackRef;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HistoryResponse = {
|
||||||
|
events: HistoryEvent[];
|
||||||
|
has_more: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exposed for direct testability (the createInfiniteQuery wrapper is harder
|
||||||
|
// to drive in unit tests without a full QueryClient harness).
|
||||||
|
export async function fetchHistoryPage(offset = 0): Promise<HistoryResponse> {
|
||||||
|
return api.get<HistoryResponse>(
|
||||||
|
`/api/me/history?offset=${offset}&limit=${HISTORY_PAGE_SIZE}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getNextPageParam(
|
||||||
|
lastPage: HistoryResponse,
|
||||||
|
_allPages: HistoryResponse[],
|
||||||
|
lastPageParam: number
|
||||||
|
): number | undefined {
|
||||||
|
return lastPage.has_more ? lastPageParam + HISTORY_PAGE_SIZE : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createHistoryQuery() {
|
||||||
|
return createInfiniteQuery({
|
||||||
|
queryKey: qk.history(),
|
||||||
|
queryFn: ({ pageParam }) => fetchHistoryPage(pageParam as number),
|
||||||
|
initialPageParam: 0,
|
||||||
|
getNextPageParam: (lastPage, allPages, lastPageParam) =>
|
||||||
|
getNextPageParam(lastPage, allPages, lastPageParam as number)
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ export const qk = {
|
|||||||
likedTracks: () => ['likedTracks'] as const,
|
likedTracks: () => ['likedTracks'] as const,
|
||||||
likedAlbums: () => ['likedAlbums'] as const,
|
likedAlbums: () => ['likedAlbums'] as const,
|
||||||
likedArtists: () => ['likedArtists'] as const,
|
likedArtists: () => ['likedArtists'] as const,
|
||||||
|
history: () => ['history'] as const,
|
||||||
// Lidarr / requests / admin.
|
// Lidarr / requests / admin.
|
||||||
lidarrSearch: (q: string, kind: string) =>
|
lidarrSearch: (q: string, kind: string) =>
|
||||||
['lidarrSearch', { q, kind }] as const,
|
['lidarrSearch', { q, kind }] as const,
|
||||||
|
|||||||
Reference in New Issue
Block a user