import { describe, expect, test, vi, beforeEach, afterEach } from 'vitest'; vi.mock('./client', () => ({ api: { get: vi.fn(), post: vi.fn(), put: vi.fn(), del: vi.fn() }, apiFetch: vi.fn() })); import { flagTrack, unflagTrack, listMyQuarantine } from './quarantine'; import { api, apiFetch } from './client'; import { qk } from './queries'; import type { LidarrQuarantineRow, LidarrQuarantineMineRow } from './types'; const mockRow: LidarrQuarantineRow = { user_id: 'u1', track_id: 't1', reason: 'bad_rip', notes: null, created_at: '2026-01-01T00:00:00Z' }; const mockMineRow: LidarrQuarantineMineRow = { track_id: 't1', reason: 'bad_rip', notes: null, created_at: '2026-01-01T00:00:00Z', track_title: 'Avril 14th', track_duration_ms: 120000, album_id: 'alb1', album_title: 'Drukqs', album_cover_art_path: null, artist_id: 'art1', artist_name: 'Aphex Twin' }; beforeEach(() => { vi.clearAllMocks(); }); afterEach(() => { vi.clearAllMocks(); }); describe('flagTrack', () => { test('POSTs /api/quarantine without notes when none provided', async () => { (api.post as ReturnType).mockResolvedValueOnce(mockRow); const out = await flagTrack({ track_id: 't1', reason: 'bad_rip' }); expect(api.post).toHaveBeenCalledWith('/api/quarantine', { track_id: 't1', reason: 'bad_rip' }); const body = (api.post as ReturnType).mock.calls[0][1] as Record< string, unknown >; expect(body).not.toHaveProperty('notes'); expect(out).toBe(mockRow); }); test('omits empty-string notes from the body', async () => { (api.post as ReturnType).mockResolvedValueOnce(mockRow); await flagTrack({ track_id: 't1', reason: 'wrong_tags', notes: '' }); const body = (api.post as ReturnType).mock.calls[0][1] as Record< string, unknown >; expect(body).toEqual({ track_id: 't1', reason: 'wrong_tags' }); expect(body).not.toHaveProperty('notes'); }); test('includes notes when a non-empty string is provided', async () => { (api.post as ReturnType).mockResolvedValueOnce(mockRow); await flagTrack({ track_id: 't1', reason: 'duplicate', notes: 'same as t0' }); expect(api.post).toHaveBeenCalledWith('/api/quarantine', { track_id: 't1', reason: 'duplicate', notes: 'same as t0' }); }); }); describe('unflagTrack', () => { test('DELETEs /api/quarantine/:trackID', async () => { (apiFetch as ReturnType).mockResolvedValueOnce(null); await unflagTrack('t1'); expect(apiFetch).toHaveBeenCalledWith('/api/quarantine/t1', { method: 'DELETE' }); }); }); describe('listMyQuarantine', () => { test('GETs /api/quarantine/mine', async () => { (api.get as ReturnType).mockResolvedValueOnce([mockMineRow]); const out = await listMyQuarantine(); expect(api.get).toHaveBeenCalledWith('/api/quarantine/mine'); expect(out).toEqual([mockMineRow]); }); }); describe('qk.myQuarantine', () => { test('returns the expected key tuple', () => { expect(qk.myQuarantine()).toEqual(['myQuarantine']); }); });