import { afterEach, describe, expect, test, vi } from 'vitest'; import { fireEvent, render, screen, waitFor } from '@testing-library/svelte'; import { mockInfiniteQuery } from '../../../test-utils/query'; import type { Download } from '#lib/api/types.js'; vi.mock('#lib/api/wanted.js', () => ({ createDownloadsQuery: vi.fn(), importAnyway: vi.fn().mockResolvedValue(undefined), retryImport: vi.fn().mockResolvedValue(undefined), refuseDownload: vi.fn().mockResolvedValue(undefined) })); vi.mock('#lib/stores/toast.svelte.js', () => ({ pushToast: vi.fn() })); import DownloadList from './DownloadList.svelte'; import { createDownloadsQuery, importAnyway, refuseDownload, retryImport } from '#lib/api/wanted.js'; const ago = (ms: number) => new Date(Date.now() - ms).toISOString(); function download(id: string, extra: Partial = {}): Download { return { id, want_id: 'w1', want_title: 'Random Access Memories', want_artist: 'Daft Punk', name: 'Daft Punk - Random Access Memories (2013) [FLAC]', indexer: 'Prowlarr', client: 'qbittorrent', quality: 'lossless', origin: 'schedule', grabbed_at: ago(3_600_000), ended_at: null, end_reason: '', progress: 0, import_state: 'downloading', import_reason: '', imported_at: null, imported_files: 0, destination: '', files: [], skipped: 0, ...extra }; } afterEach(() => vi.clearAllMocks()); function setup(items: Download[]) { vi.mocked(createDownloadsQuery).mockReturnValue( mockInfiniteQuery({ pages: [{ items, total: items.length, limit: 50, offset: 0 }] }) as unknown as ReturnType< typeof createDownloadsQuery > ); return render(DownloadList); } describe('DownloadList', () => { test('a running download shows how far it has got', () => { setup([download('d1', { progress: 0.375 })]); expect(screen.getByTestId('download-state').textContent).toMatch(/downloading/i); expect(screen.getByRole('progressbar', { name: /downloaded/i }).getAttribute('aria-valuenow')).toBe('37'); expect(screen.queryByRole('button')).toBeNull(); }); test('a doubtful download says why and can be imported anyway or refused', async () => { setup([ download('d1', { import_state: 'review', import_reason: 'Only the lengths agree. A person decides.', evidence: { files: 13, tracks: 13, identified: 0, recordings: 0, lengths: 13, titles: 0, fingerprinted: false } }) ]); expect(screen.getByTestId('download-state').textContent).toMatch(/needs you/i); expect(screen.getByTestId('download-reason').textContent).toMatch(/a person decides/i); expect(screen.getByText(/13 files against 13 tracks · no AcoustID · 13 lengths agree/)).toBeTruthy(); await fireEvent.click(screen.getByRole('button', { name: /import anyway/i })); await waitFor(() => expect(importAnyway).toHaveBeenCalledWith('d1')); await fireEvent.click(screen.getByRole('button', { name: /refuse/i })); await waitFor(() => expect(refuseDownload).toHaveBeenCalledWith('d1')); }); test('a failed import can be tried again', async () => { setup([download('d1', { import_state: 'failed', import_reason: 'The library folder is not writable.' })]); expect(screen.queryByRole('button', { name: /import anyway/i })).toBeNull(); await fireEvent.click(screen.getByRole('button', { name: /try again/i })); await waitFor(() => expect(retryImport).toHaveBeenCalledWith('d1')); }); test('an imported download says what was filed where', () => { setup([ download('d1', { ended_at: ago(60_000), end_reason: 'imported', import_state: 'imported', imported_at: ago(60_000), imported_files: 12, skipped: 1, destination: '/music/Daft Punk/Random Access Memories (2013)' }) ]); expect(screen.getByTestId('download-state').textContent).toMatch(/imported/i); expect(screen.getByText(/12 tracks filed, 1 already held into \/music\/Daft Punk/)).toBeTruthy(); expect(screen.queryByRole('button')).toBeNull(); }); test('with nothing downloaded it says what lands here', () => { setup([]); expect(screen.getByText(/nothing has been downloaded yet/i)).toBeTruthy(); }); });