// Copyright (c) 2026 Gordon Bolton. MIT License. import { describe, it, expect } from 'vitest'; const { getRequestStatus, filterByType, filterByStatus, filterBySearch, sortRequests, applyRequestFilters } = require('../../server/utils/ombiFilters'); function makeRequest(overrides = {}) { return { id: 1, title: 'Test Request', requestedDate: '2026-05-21T10:00:00.000Z', available: false, approved: false, denied: false, requested: true, mediaType: 'movie', ...overrides }; } // --------------------------------------------------------------------------- // getRequestStatus // --------------------------------------------------------------------------- describe('getRequestStatus', () => { it('returns available when available is true', () => { expect(getRequestStatus(makeRequest({ available: true }))).toBe('available'); }); it('returns denied when denied is true', () => { expect(getRequestStatus(makeRequest({ denied: true }))).toBe('denied'); }); it('returns approved when approved is true', () => { expect(getRequestStatus(makeRequest({ approved: true }))).toBe('approved'); }); it('returns pending when requested is true', () => { expect(getRequestStatus(makeRequest({ requested: true }))).toBe('pending'); }); it('returns unknown for empty object', () => { expect(getRequestStatus({})).toBe('unknown'); }); it('returns unknown for null', () => { expect(getRequestStatus(null)).toBe('unknown'); }); it('follows priority: available > denied > approved > pending', () => { expect(getRequestStatus(makeRequest({ available: true, denied: true }))).toBe('available'); expect(getRequestStatus(makeRequest({ denied: true, approved: true }))).toBe('denied'); expect(getRequestStatus(makeRequest({ approved: true, requested: true }))).toBe('approved'); }); it('returns available from childRequests when top-level is absent (TV)', () => { expect(getRequestStatus({ childRequests: [{ available: true }] })).toBe('available'); }); it('returns denied from childRequests when top-level is absent (TV)', () => { expect(getRequestStatus({ childRequests: [{ denied: true }] })).toBe('denied'); }); it('returns approved from childRequests when top-level is absent (TV)', () => { expect(getRequestStatus({ childRequests: [{ approved: true }] })).toBe('approved'); }); it('returns pending from childRequests when top-level is absent (TV)', () => { expect(getRequestStatus({ childRequests: [{ requested: true }] })).toBe('pending'); }); it('follows priority inside childRequests: available > denied > approved > pending', () => { expect(getRequestStatus({ childRequests: [ { available: true, denied: true }, { approved: true } ]})).toBe('available'); expect(getRequestStatus({ childRequests: [ { denied: true, approved: true }, { requested: true } ]})).toBe('denied'); expect(getRequestStatus({ childRequests: [ { approved: true, requested: true } ]})).toBe('approved'); }); it('returns unknown for TV request with empty childRequests', () => { expect(getRequestStatus({ childRequests: [] })).toBe('unknown'); }); }); // --------------------------------------------------------------------------- // filterByType // --------------------------------------------------------------------------- describe('filterByType', () => { const movie = makeRequest({ mediaType: 'movie' }); const tv = makeRequest({ mediaType: 'tv', id: 2 }); it('returns all when types is empty', () => { expect(filterByType([movie, tv], [])).toEqual([movie, tv]); }); it('returns all when types includes "all"', () => { expect(filterByType([movie, tv], ['all'])).toEqual([movie, tv]); }); it('filters to movies only', () => { expect(filterByType([movie, tv], ['movie'])).toEqual([movie]); }); it('filters to tv only', () => { expect(filterByType([movie, tv], ['tv'])).toEqual([tv]); }); it('is case-insensitive', () => { expect(filterByType([movie, tv], ['MOVIE'])).toEqual([movie]); }); it('handles empty array', () => { expect(filterByType([], ['movie'])).toEqual([]); }); }); // --------------------------------------------------------------------------- // filterByStatus // --------------------------------------------------------------------------- describe('filterByStatus', () => { const pending = makeRequest({ requested: true }); const approved = makeRequest({ approved: true, requested: true, id: 2 }); const available = makeRequest({ available: true, id: 3 }); it('returns all when statuses is empty', () => { expect(filterByStatus([pending, approved], [])).toEqual([pending, approved]); }); it('filters by single status', () => { expect(filterByStatus([pending, approved], ['approved'])).toEqual([approved]); }); it('filters by multiple statuses', () => { expect(filterByStatus([pending, approved, available], ['pending', 'available'])).toEqual([pending, available]); }); it('is case-insensitive', () => { expect(filterByStatus([pending], ['PENDING'])).toEqual([pending]); }); it('handles empty array', () => { expect(filterByStatus([], ['pending'])).toEqual([]); }); }); // --------------------------------------------------------------------------- // filterBySearch // --------------------------------------------------------------------------- describe('filterBySearch', () => { const batman = makeRequest({ title: 'The Batman' }); const superman = makeRequest({ title: 'Superman', id: 2 }); it('returns all when query is empty', () => { expect(filterBySearch([batman, superman], '')).toEqual([batman, superman]); }); it('returns all when query is whitespace', () => { expect(filterBySearch([batman, superman], ' ')).toEqual([batman, superman]); }); it('filters by case-insensitive substring', () => { expect(filterBySearch([batman, superman], 'bat')).toEqual([batman]); expect(filterBySearch([batman, superman], 'BAT')).toEqual([batman]); }); it('handles missing title', () => { expect(filterBySearch([makeRequest({ title: undefined })], 'test')).toEqual([]); }); it('handles empty array', () => { expect(filterBySearch([], 'test')).toEqual([]); }); }); // --------------------------------------------------------------------------- // sortRequests // --------------------------------------------------------------------------- describe('sortRequests', () => { const oldReq = makeRequest({ id: 1, title: 'Alpha', requestedDate: '2026-01-01T00:00:00.000Z' }); const midReq = makeRequest({ id: 2, title: 'Beta', requestedDate: '2026-05-01T00:00:00.000Z' }); const newReq = makeRequest({ id: 3, title: 'Charlie', requestedDate: '2026-10-01T00:00:00.000Z' }); it('sorts newest to oldest by default', () => { const sorted = sortRequests([oldReq, newReq, midReq], 'requestedDate_desc'); expect(sorted.map(r => r.id)).toEqual([3, 2, 1]); }); it('sorts oldest to newest', () => { const sorted = sortRequests([oldReq, newReq, midReq], 'requestedDate_asc'); expect(sorted.map(r => r.id)).toEqual([1, 2, 3]); }); it('sorts A-Z', () => { const sorted = sortRequests([midReq, oldReq, newReq], 'title_asc'); expect(sorted.map(r => r.title)).toEqual(['Alpha', 'Beta', 'Charlie']); }); it('sorts Z-A', () => { const sorted = sortRequests([midReq, oldReq, newReq], 'title_desc'); expect(sorted.map(r => r.title)).toEqual(['Charlie', 'Beta', 'Alpha']); }); it('defaults to requestedDate_desc for unknown sort mode', () => { const sorted = sortRequests([oldReq, newReq], 'invalid'); expect(sorted.map(r => r.id)).toEqual([3, 1]); }); it('handles missing requestedDate by treating as epoch 0', () => { const noDate = makeRequest({ id: 4, requestedDate: undefined }); const sorted = sortRequests([midReq, noDate], 'requestedDate_desc'); expect(sorted[0]).toBe(midReq); expect(sorted[1]).toBe(noDate); }); it('handles missing title', () => { const noTitle = makeRequest({ id: 4, title: undefined }); const withTitle = makeRequest({ id: 5, title: 'Zebra' }); const sorted = sortRequests([noTitle, withTitle], 'title_asc'); expect(sorted[0]).toBe(noTitle); expect(sorted[1]).toBe(withTitle); }); }); // --------------------------------------------------------------------------- // applyRequestFilters // --------------------------------------------------------------------------- describe('applyRequestFilters', () => { const moviePending = makeRequest({ id: 1, title: 'The Batman', mediaType: 'movie', requested: true, approved: false }); const tvApproved = makeRequest({ id: 2, title: 'Superman Show', mediaType: 'tv', approved: true, requested: false }); const movieAvailable = makeRequest({ id: 3, title: 'Batman Returns', mediaType: 'movie', available: true }); it('applies all filters together', () => { const result = applyRequestFilters( [moviePending, tvApproved, movieAvailable], { types: ['movie'], statuses: ['pending', 'available'], sort: 'title_asc', search: 'bat' } ); expect(result.map(r => r.id)).toEqual([3, 1]); }); it('returns unfiltered when no options provided', () => { const result = applyRequestFilters([moviePending, tvApproved], {}); expect(result).toEqual([moviePending, tvApproved]); }); it('returns empty array when no matches', () => { const result = applyRequestFilters( [moviePending], { types: ['tv'] } ); expect(result).toEqual([]); }); });