/** * Tests for External Folder functionality in FileManagerPage. */ import { describe, it, expect, beforeEach } from 'vitest'; import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { render } from '../utils'; import { FileManagerPage } from '../../pages/FileManagerPage'; import { http, HttpResponse } from 'msw'; import { server } from '../mocks/server'; // Mock data with external folder const mockFoldersWithExternal = [ { id: 1, name: 'Regular Folder', parent_id: null, file_count: 3, project_id: null, archive_id: null, project_name: null, archive_name: null, is_external: false, external_path: null, external_readonly: false, children: [], }, { id: 2, name: 'NAS Prints', parent_id: null, file_count: 5, project_id: null, archive_id: null, project_name: null, archive_name: null, is_external: true, external_path: '/mnt/nas/prints', external_readonly: true, children: [], }, { id: 3, name: 'USB Drive', parent_id: null, file_count: 2, project_id: null, archive_id: null, project_name: null, archive_name: null, is_external: true, external_path: '/mnt/usb', external_readonly: false, children: [], }, ]; const mockFiles = [ { id: 1, filename: 'benchy.3mf', file_path: '/mnt/nas/prints/benchy.3mf', file_size: 1048576, file_type: '3mf', folder_id: 2, is_external: true, thumbnail_path: null, print_name: 'Benchy', print_time_seconds: 3600, print_count: 0, duplicate_count: 0, created_at: '2024-01-01T00:00:00Z', }, ]; const mockStats = { total_files: 10, total_folders: 3, total_size_bytes: 104857600, disk_free_bytes: 10737418240, disk_total_bytes: 107374182400, }; describe('FileManagerPage - External Folders', () => { beforeEach(() => { localStorage.clear(); server.use( http.get('/api/v1/library/folders', () => { return HttpResponse.json(mockFoldersWithExternal); }), http.get('/api/v1/library/files', () => { return HttpResponse.json(mockFiles); }), http.get('/api/v1/library/stats', () => { return HttpResponse.json(mockStats); }), http.get('/api/v1/settings/', () => { return HttpResponse.json({ check_updates: false, check_printer_firmware: false, library_disk_warning_gb: 5, }); }), http.post('/api/v1/library/folders/external', async ({ request }) => { const body = await request.json() as { name: string; external_path: string }; return HttpResponse.json({ id: 10, name: body.name, parent_id: null, is_external: true, external_path: body.external_path, external_readonly: true, external_show_hidden: false, file_count: 0, created_at: '2024-01-01T00:00:00Z', updated_at: '2024-01-01T00:00:00Z', }); }), http.post('/api/v1/library/folders/:id/scan', () => { return HttpResponse.json({ status: 'success', added: 3, removed: 0 }); }), http.get('/api/v1/projects/', () => { return HttpResponse.json([]); }), http.get('/api/v1/archives/', () => { return HttpResponse.json([]); }), http.delete('/api/v1/library/folders/:id', () => { return HttpResponse.json({ success: true }); }), http.delete('/api/v1/library/files/:id', () => { return HttpResponse.json({ success: true }); }), http.post('/api/v1/library/files/move', () => { return HttpResponse.json({ success: true }); }), ); }); describe('rendering', () => { it('shows Link External button', async () => { render(); await waitFor(() => { expect(screen.getByText('Link External')).toBeInTheDocument(); }); }); it('shows external folder in sidebar', async () => { render(); await waitFor(() => { expect(screen.getByText('NAS Prints')).toBeInTheDocument(); expect(screen.getByText('USB Drive')).toBeInTheDocument(); }); }); it('shows regular folder alongside external', async () => { render(); await waitFor(() => { expect(screen.getByText('Regular Folder')).toBeInTheDocument(); expect(screen.getByText('NAS Prints')).toBeInTheDocument(); }); }); it('shows read-only indicator for readonly external folders', async () => { render(); await waitFor(() => { // NAS Prints is readonly, should have a lock icon title const lockIcons = document.querySelectorAll('[title="Read Only"]'); expect(lockIcons.length).toBeGreaterThan(0); }); }); }); describe('external folder modal', () => { it('opens modal when Link External clicked', async () => { const user = userEvent.setup(); render(); await waitFor(() => { expect(screen.getByText('Link External')).toBeInTheDocument(); }); await user.click(screen.getByText('Link External')); await waitFor(() => { expect(screen.getByText('Link External Folder')).toBeInTheDocument(); }); }); it('modal has name and path fields', async () => { const user = userEvent.setup(); render(); await waitFor(() => { expect(screen.getByText('Link External')).toBeInTheDocument(); }); await user.click(screen.getByText('Link External')); await waitFor(() => { expect(screen.getByPlaceholderText('e.g., NAS Prints')).toBeInTheDocument(); expect(screen.getByPlaceholderText('/mnt/nas/3d-prints')).toBeInTheDocument(); }); }); it('modal has readonly checkbox checked by default', async () => { const user = userEvent.setup(); render(); await waitFor(() => { expect(screen.getByText('Link External')).toBeInTheDocument(); }); await user.click(screen.getByText('Link External')); await waitFor(() => { const readonlyCheckbox = screen.getByText('Read Only').previousElementSibling as HTMLInputElement; expect(readonlyCheckbox).toBeChecked(); }); }); it('modal can be closed', async () => { const user = userEvent.setup(); render(); await waitFor(() => { expect(screen.getByText('Link External')).toBeInTheDocument(); }); await user.click(screen.getByText('Link External')); await waitFor(() => { expect(screen.getByText('Link External Folder')).toBeInTheDocument(); }); await user.click(screen.getByText('Cancel')); await waitFor(() => { expect(screen.queryByText('Link External Folder')).not.toBeInTheDocument(); }); }); }); describe('external folder info bar', () => { it('shows info bar when external folder selected', async () => { const user = userEvent.setup(); render(); await waitFor(() => { expect(screen.getByText('NAS Prints')).toBeInTheDocument(); }); // Click on NAS Prints folder - there are multiple elements, get the one in the sidebar const folderElements = screen.getAllByText('NAS Prints'); await user.click(folderElements[0]); await waitFor(() => { expect(screen.getByText('External Folder')).toBeInTheDocument(); expect(screen.getByText('/mnt/nas/prints')).toBeInTheDocument(); }); }); it('shows scan button for external folders', async () => { const user = userEvent.setup(); render(); await waitFor(() => { expect(screen.getByText('NAS Prints')).toBeInTheDocument(); }); const folderElements = screen.getAllByText('NAS Prints'); await user.click(folderElements[0]); await waitFor(() => { expect(screen.getByText('Scan')).toBeInTheDocument(); }); }); it('does not show info bar for regular folders', async () => { const user = userEvent.setup(); render(); await waitFor(() => { expect(screen.getByText('Regular Folder')).toBeInTheDocument(); }); const folderElements = screen.getAllByText('Regular Folder'); await user.click(folderElements[0]); // External Folder label should NOT appear await waitFor(() => { expect(screen.queryByText('External Folder')).not.toBeInTheDocument(); }); }); }); });