import { describe, it, expect, vi, beforeEach } from 'vitest'; import FileListManager from '../utils/renderer/FileListManager'; describe('FileListManager', () => { let fileListEl; let flm; let folderClickSpy; beforeEach(() => { fileListEl = document.createElement('div'); fileListEl.id = 'file-list'; folderClickSpy = vi.fn(); flm = new FileListManager(fileListEl, folderClickSpy); }); describe('constructor', () => { it('initializes with null draggedItem', () => { expect(flm.draggedItem).toBeNull(); }); it('accepts null folder click callback', () => { const manager = new FileListManager(fileListEl, null); expect(manager.onFolderClick).toBeNull(); }); }); describe('displayFiles', () => { it('shows empty message when no files', () => { flm.displayFiles([]); expect(fileListEl.textContent).toContain('No media files found'); }); it('displays folders and media files', () => { const files = [ { isFolder: true, path: '/path/folder', name: 'Extras' }, { isFolder: false, path: '/path/file.mp4', name: 'episode.mp4', duration: '45:00', quality: '1080p', fps: '30fps' }, ]; flm.displayFiles(files); const items = fileListEl.querySelectorAll('.file-item'); expect(items.length).toBe(2); expect(items[0].classList.contains('folder-item')).toBe(true); }); it('sorts folders before files', () => { const files = [ { isFolder: false, path: '/path/file.mp4', name: 'episode.mp4', duration: '45:00' }, { isFolder: true, path: '/path/folder', name: 'Extras' }, ]; flm.displayFiles(files); const items = fileListEl.querySelectorAll('.file-item'); expect(items[0].classList.contains('folder-item')).toBe(true); }); it('creates folder element with click handler', () => { const files = [{ isFolder: true, path: '/path/folder', name: 'Extras' }]; flm.displayFiles(files); const folderItem = fileListEl.querySelector('.folder-item'); expect(folderItem).not.toBeNull(); }); it('creates media file with episode number', () => { const files = [ { isFolder: false, path: '/path/file.mp4', name: 'episode.mp4', duration: '45:00', quality: '1080p', fps: '30fps' }, ]; flm.displayFiles(files); const episodeEl = fileListEl.querySelector('.episode-number'); expect(episodeEl).not.toBeNull(); expect(episodeEl.textContent).toBe('1'); }); it('marks problematic files with warning icon', () => { const files = [ { isFolder: false, path: '/path/bad.mp4', name: 'bad.mp4', duration: '00:00', isProblematic: true }, ]; flm.displayFiles(files); const warnLabel = fileListEl.querySelector('.problematic-label'); expect(warnLabel).not.toBeNull(); }); }); describe('updateEpisodeNumbers', () => { it('updates episode numbers sequentially', () => { const files = [ { isFolder: false, path: '/path/f1.mp4', name: 'f1.mp4' }, { isFolder: false, path: '/path/f2.mp4', name: 'f2.mp4' }, { isFolder: false, path: '/path/f3.mp4', name: 'f3.mp4' }, ]; flm.displayFiles(files); flm.updateEpisodeNumbers(); const episodeEls = fileListEl.querySelectorAll('.episode-number'); expect(episodeEls[0].textContent).toBe('1'); expect(episodeEls[1].textContent).toBe('2'); expect(episodeEls[2].textContent).toBe('3'); }); }); describe('clear', () => { it('clears the file list', () => { const files = [ { isFolder: false, path: '/path/f1.mp4', name: 'f1.mp4' }, ]; flm.displayFiles(files); flm.clear(); expect(fileListEl.innerHTML).toBe(''); }); }); describe('getMediaFileItems', () => { it('returns only media file items', () => { const files = [ { isFolder: true, path: '/path/folder', name: 'Folder' }, { isFolder: false, path: '/path/file.mp4', name: 'file.mp4' }, ]; flm.displayFiles(files); const mediaItems = flm.getMediaFileItems(); expect(mediaItems.length).toBe(1); }); }); describe('getFolderItems', () => { it('returns only folder items', () => { const files = [ { isFolder: true, path: '/path/folder', name: 'Folder' }, { isFolder: false, path: '/path/file.mp4', name: 'file.mp4' }, ]; flm.displayFiles(files); const folderItems = flm.getFolderItems(); expect(folderItems.length).toBe(1); }); }); describe('highlightFilesMatchingEpisode', () => { it('highlights matching episodes', () => { const files = [ { isFolder: false, path: '/path/f1.mp4', name: 'f1.mp4' }, { isFolder: false, path: '/path/f2.mp4', name: 'f2.mp4' }, { isFolder: false, path: '/path/f3.mp4', name: 'f3.mp4' }, ]; flm.displayFiles(files); flm.highlightFilesMatchingEpisode(2, 2); const items = flm.getMediaFileItems(); expect(items[0].classList.contains('hovered-file')).toBe(false); expect(items[1].classList.contains('hovered-file')).toBe(true); expect(items[2].classList.contains('hovered-file')).toBe(false); }); it('highlights overlapping ranges', () => { const files = [ { isFolder: false, path: '/path/f1.mp4', name: 'f1.mp4' }, { isFolder: false, path: '/path/f2.mp4', name: 'f2.mp4' }, ]; flm.displayFiles(files); // Update first file to have range 1-2 const firstEp = flm.getMediaFileItems()[0].querySelector('.episode-number'); firstEp.dataset.episodeEnd = '2'; flm.highlightFilesMatchingEpisode(1, 1); const items = flm.getMediaFileItems(); // File 1 (range 1-2) overlaps with hover range 1-1 expect(items[0].classList.contains('hovered-file')).toBe(true); // File 2 (range 2-2) does NOT overlap with hover range 1-1 expect(items[1].classList.contains('hovered-file')).toBe(false); }); }); describe('removeFileHighlights', () => { it('removes all highlights', () => { const files = [ { isFolder: false, path: '/path/f1.mp4', name: 'f1.mp4' }, ]; flm.displayFiles(files); flm.highlightFilesMatchingEpisode(1, 1); flm.removeFileHighlights(); const items = flm.getMediaFileItems(); expect(items[0].classList.contains('hovered-file')).toBe(false); }); }); describe('setFolderClickCallback', () => { it('updates the callback', () => { const newCallback = vi.fn(); flm.setFolderClickCallback(newCallback); expect(flm.onFolderClick).toBe(newCallback); }); }); describe('folder click handling', () => { it('calls folder click callback when folder is clicked', () => { const files = [{ isFolder: true, path: '/path/folder', name: 'Extras' }]; flm.displayFiles(files); const folderItem = fileListEl.querySelector('.folder-item'); folderItem.click(); expect(folderClickSpy).toHaveBeenCalledWith('/path/folder', 'Extras'); }); }); });