// Copyright (c) 2026 Gordon Bolton. MIT License. import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import nock from 'nock'; import PollingRadarrRetriever from '../../../server/clients/PollingRadarrRetriever'; describe('PollingRadarrRetriever', () => { const config = { id: 'radarr-test', name: 'Test Radarr', url: 'http://radarr-mock.test', apiKey: 'mock-api-key' }; let retriever; beforeEach(() => { retriever = new PollingRadarrRetriever(config); nock.disableNetConnect(); }); afterEach(() => { nock.cleanAll(); nock.enableNetConnect(); }); it('should return correct type and instance ID', () => { expect(retriever.getRetrieverType()).toBe('radarr'); expect(retriever.getInstanceId()).toBe('radarr-test'); }); describe('getTags', () => { it('should fetch tags successfully', async () => { const mockTags = [{ id: 1, label: 'tag1' }, { id: 2, label: 'tag2' }]; nock(config.url) .get('/api/v3/tag') .matchHeader('X-Api-Key', config.apiKey) .reply(200, mockTags); const tags = await retriever.getTags(); expect(tags).toEqual(mockTags); }); it('should return an empty array on error and log it', async () => { nock(config.url) .get('/api/v3/tag') .reply(500, 'Internal Server Error'); const tags = await retriever.getTags(); expect(tags).toEqual([]); }); }); describe('getQueue', () => { it('should fetch queue in a single page if records count is less than 1000', async () => { const mockQueueResponse = { page: 1, pageSize: 1000, totalRecords: 2, records: [ { id: 1, title: 'Movie 1' }, { id: 2, title: 'Movie 2' } ] }; nock(config.url) .get('/api/v3/queue') .query({ includeMovie: 'true', page: 1, pageSize: 1000 }) .matchHeader('X-Api-Key', config.apiKey) .reply(200, mockQueueResponse); const queue = await retriever.getQueue(); expect(queue.records).toHaveLength(2); expect(queue.records).toEqual(mockQueueResponse.records); }); it('should paginate queue if the page size is exactly 1000', async () => { const page1Records = Array.from({ length: 1000 }, (_, i) => ({ id: i, title: `Movie ${i}` })); const page2Records = [{ id: 1000, title: 'Movie 1000' }]; nock(config.url) .get('/api/v3/queue') .query({ includeMovie: 'true', page: 1, pageSize: 1000 }) .reply(200, { page: 1, pageSize: 1000, totalRecords: 1001, records: page1Records }); nock(config.url) .get('/api/v3/queue') .query({ includeMovie: 'true', page: 2, pageSize: 1000 }) .reply(200, { page: 2, pageSize: 1000, totalRecords: 1001, records: page2Records }); const queue = await retriever.getQueue(); expect(queue.records).toHaveLength(1001); expect(queue.records[1000]).toEqual(page2Records[0]); }); it('should throw an error if the request fails', async () => { nock(config.url) .get('/api/v3/queue') .query(true) .reply(500, 'Server Error'); await expect(retriever.getQueue()).rejects.toThrow(); }); }); describe('getHistory', () => { it('should fetch history with default parameters', async () => { const mockHistoryResponse = { page: 1, pageSize: 100, totalRecords: 2, records: [ { id: 1, eventType: 'grabbed' }, { id: 2, eventType: 'downloadFolderImported' } ] }; nock(config.url) .get('/api/v3/history') .query({ page: 1, pageSize: 100, includeMovie: 'true' }) .matchHeader('X-Api-Key', config.apiKey) .reply(200, mockHistoryResponse); const history = await retriever.getHistory(); expect(history.records).toHaveLength(2); expect(history.records).toEqual(mockHistoryResponse.records); }); it('should apply sorting and startDate filters from options', async () => { const mockHistoryResponse = { page: 1, pageSize: 10, totalRecords: 0, records: [] }; nock(config.url) .get('/api/v3/history') .query({ page: 1, pageSize: 10, includeMovie: 'false', sortKey: 'date', sortDir: 'descending', startDate: '2026-05-22T00:00:00Z' }) .reply(200, mockHistoryResponse); const history = await retriever.getHistory({ pageSize: 10, includeMovie: false, sortKey: 'date', sortDir: 'descending', startDate: '2026-05-22T00:00:00Z' }); expect(history.records).toEqual([]); }); it('should paginate history when more pages are available up to maxPages', async () => { const page1Records = Array.from({ length: 50 }, (_, i) => ({ id: i })); const page2Records = Array.from({ length: 50 }, (_, i) => ({ id: 50 + i })); nock(config.url) .get('/api/v3/history') .query({ page: 1, pageSize: 50, includeMovie: 'true' }) .reply(200, { page: 1, pageSize: 50, records: page1Records }); nock(config.url) .get('/api/v3/history') .query({ page: 2, pageSize: 50, includeMovie: 'true' }) .reply(200, { page: 2, pageSize: 50, records: page2Records }); const history = await retriever.getHistory({ pageSize: 50, maxPages: 2 }); expect(history.records).toHaveLength(100); }); it('should throw an error on API failure', async () => { nock(config.url) .get('/api/v3/history') .query(true) .reply(500, 'Server Error'); await expect(retriever.getHistory()).rejects.toThrow(); }); }); });