import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { api, ApiError } from '../src/api' const fetchMock = vi.fn() beforeEach(() => vi.stubGlobal('fetch', fetchMock)) afterEach(() => vi.unstubAllGlobals()) function jsonOk(body: unknown) { return Promise.resolve(new Response(JSON.stringify(body), { status: 200, headers: { 'content-type': 'application/json' } })) } describe('api additions', () => { it('album tracks + played + stream url', async () => { fetchMock.mockImplementation(() => jsonOk({ id: 'a1', title: 'Motion', artist: 'TCO', tracks: [] })) await api.getAlbumTracks('a1') expect(fetchMock).toHaveBeenCalledWith('/api/album/a1/tracks', expect.anything()) await api.markPlayed('a1') expect(fetchMock).toHaveBeenCalledWith('/api/album/a1/played', expect.objectContaining({ method: 'POST' })) expect(api.streamUrl('s 1')).toBe('/api/stream/s%201') }) it('stats, loans, backups urls', async () => { fetchMock.mockImplementation(() => jsonOk({})) await api.getStats() expect(fetchMock).toHaveBeenCalledWith('/api/stats', expect.anything()) await api.lendItem(5, 'Bob') expect(fetchMock).toHaveBeenCalledWith('/api/collection/5/loan', expect.objectContaining({ method: 'POST' })) await api.returnLoan(7) expect(fetchMock).toHaveBeenCalledWith('/api/loans/7/return', expect.objectContaining({ method: 'POST' })) await api.getBackups() expect(fetchMock).toHaveBeenCalledWith('/api/backups', expect.anything()) expect(api.exportUrl()).toBe('/api/export') }) it('surfaces subsonic errors as ApiError', async () => { fetchMock.mockReturnValue( Promise.resolve(new Response(JSON.stringify({ error: 'no_subsonic_config' }), { status: 409 })) ) const err = await api.getAlbumTracks('a1').catch((e) => e) expect(err).toBeInstanceOf(ApiError) expect((err as ApiError).code).toBe('no_subsonic_config') }) it('bodyless posts do not send a json content-type (Fastify 400s on empty json bodies)', async () => { fetchMock.mockClear() fetchMock.mockImplementation(() => jsonOk({ ok: true })) await api.returnLoan(7) await api.markPlayed('a1') await api.logout() await api.triggerBackup() for (const call of fetchMock.mock.calls) { const init = call[1] as RequestInit | undefined const headers = (init?.headers ?? {}) as Record expect(headers['Content-Type']).toBeUndefined() expect(init?.body).toBeUndefined() } }) })