import { expect } from '@playwright/test' import { comfyPageFixture as test } from '@e2e/fixtures/ComfyPage' const MOCK_FOLDERS: Record = { checkpoints: [ 'sd_xl_base_1.0.safetensors', 'dreamshaper_8.safetensors', 'realisticVision_v51.safetensors' ], loras: ['detail_tweaker_xl.safetensors', 'add_brightness.safetensors'], vae: ['sdxl_vae.safetensors'] } // ========================================================================== // 1. Tab open/close // ========================================================================== test.describe('Model library sidebar - tab', () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.modelLibrary.mockFoldersWithFiles(MOCK_FOLDERS) await comfyPage.setup() }) test.afterEach(async ({ comfyPage }) => { await comfyPage.modelLibrary.clearMocks() }) test('Opens model library tab and shows tree', async ({ comfyPage }) => { const tab = comfyPage.menu.modelLibraryTab await tab.open() await expect(tab.modelTree).toBeVisible() await expect(tab.searchInput).toBeVisible() }) test('Shows refresh and load all folders buttons', async ({ comfyPage }) => { const tab = comfyPage.menu.modelLibraryTab await tab.open() await expect(tab.refreshButton).toBeVisible() await expect(tab.loadAllFoldersButton).toBeVisible() }) }) // ========================================================================== // 2. Folder display // ========================================================================== test.describe('Model library sidebar - folders', () => { // Mocks are set up before setup(), so app.ts's loadModelFolders() // call during initialization hits the mock and populates the store. test.beforeEach(async ({ comfyPage }) => { await comfyPage.modelLibrary.mockFoldersWithFiles(MOCK_FOLDERS) await comfyPage.setup() }) test.afterEach(async ({ comfyPage }) => { await comfyPage.modelLibrary.clearMocks() }) test('Displays model folders after opening tab', async ({ comfyPage }) => { const tab = comfyPage.menu.modelLibraryTab await tab.open() await expect(tab.getFolderByLabel('checkpoints')).toBeVisible() await expect(tab.getFolderByLabel('loras')).toBeVisible() await expect(tab.getFolderByLabel('vae')).toBeVisible() }) test('Expanding a folder loads and shows models', async ({ comfyPage }) => { const tab = comfyPage.menu.modelLibraryTab await tab.open() // Click the folder to expand it await tab.getFolderByLabel('checkpoints').click() // Models should appear as leaf nodes await expect(tab.getLeafByLabel('sd_xl_base_1.0')).toBeVisible() await expect(tab.getLeafByLabel('dreamshaper_8')).toBeVisible() await expect(tab.getLeafByLabel('realisticVision_v51')).toBeVisible() }) test('Expanding a different folder shows its models', async ({ comfyPage }) => { const tab = comfyPage.menu.modelLibraryTab await tab.open() await tab.getFolderByLabel('loras').click() await expect(tab.getLeafByLabel('detail_tweaker_xl')).toBeVisible() await expect(tab.getLeafByLabel('add_brightness')).toBeVisible() }) }) // ========================================================================== // 3. Search // ========================================================================== test.describe('Model library sidebar - search', () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.modelLibrary.mockFoldersWithFiles(MOCK_FOLDERS) await comfyPage.setup() }) test.afterEach(async ({ comfyPage }) => { await comfyPage.modelLibrary.clearMocks() }) test('Search filters models by filename', async ({ comfyPage }) => { const tab = comfyPage.menu.modelLibraryTab await tab.open() await tab.searchInput.fill('dreamshaper') // Wait for debounce (300ms) + load + render await expect(tab.getLeafByLabel('dreamshaper_8')).toBeVisible() // Other models should not be visible await expect(tab.getLeafByLabel('sd_xl_base_1.0')).toBeHidden() }) test('Clearing search restores folder view', async ({ comfyPage }) => { const tab = comfyPage.menu.modelLibraryTab await tab.open() await tab.searchInput.fill('dreamshaper') await expect(tab.getLeafByLabel('dreamshaper_8')).toBeVisible() // Clear the search await tab.searchInput.fill('') // Folders should be visible again (collapsed) await expect(tab.getFolderByLabel('checkpoints')).toBeVisible() await expect(tab.getFolderByLabel('loras')).toBeVisible() }) test('Search with no matches shows empty tree', async ({ comfyPage }) => { const tab = comfyPage.menu.modelLibraryTab await tab.open() // Expand a folder and verify models are present before searching await tab.getFolderByLabel('checkpoints').click() await expect(tab.leafNodes).not.toHaveCount(0) await tab.searchInput.fill('nonexistent_model_xyz') // Wait for debounce, then verify no leaf nodes await expect.poll(() => tab.leafNodes.count()).toBe(0) }) }) // ========================================================================== // 4. Refresh and load all // ========================================================================== test.describe('Model library sidebar - refresh', () => { test.afterEach(async ({ comfyPage }) => { await comfyPage.modelLibrary.clearMocks() }) test('Refresh button reloads folder list', async ({ comfyPage }) => { await comfyPage.modelLibrary.mockFoldersWithFiles({ checkpoints: ['model_a.safetensors'] }) await comfyPage.setup() const tab = comfyPage.menu.modelLibraryTab await tab.open() await expect(tab.getFolderByLabel('checkpoints')).toBeVisible() // Update mock to include a new folder await comfyPage.modelLibrary.clearMocks() await comfyPage.modelLibrary.mockFoldersWithFiles({ checkpoints: ['model_a.safetensors'], loras: ['lora_b.safetensors'] }) // Wait for the refresh request to complete const refreshRequest = comfyPage.page.waitForRequest( (req) => req.url().endsWith('/experiment/models'), { timeout: 5000 } ) await tab.refreshButton.click() await refreshRequest await expect(tab.getFolderByLabel('loras')).toBeVisible() }) test('Load all folders button triggers loading all model data', async ({ comfyPage }) => { await comfyPage.modelLibrary.mockFoldersWithFiles(MOCK_FOLDERS) await comfyPage.setup() const tab = comfyPage.menu.modelLibraryTab await tab.open() // Wait for a per-folder model files request triggered by load all const folderRequest = comfyPage.page.waitForRequest( (req) => /\/api\/experiment\/models\/[^/]+$/.test(req.url()) && req.method() === 'GET', { timeout: 5000 } ) await tab.loadAllFoldersButton.click() await folderRequest }) }) // ========================================================================== // 5. Empty state // ========================================================================== test.describe('Model library sidebar - empty state', () => { test.afterEach(async ({ comfyPage }) => { await comfyPage.modelLibrary.clearMocks() }) test('Shows empty tree when no model folders exist', async ({ comfyPage }) => { await comfyPage.modelLibrary.mockFoldersWithFiles({}) await comfyPage.setup() const tab = comfyPage.menu.modelLibraryTab await tab.open() await expect(tab.modelTree).toBeVisible() await expect(tab.folderNodes).toHaveCount(0) await expect(tab.leafNodes).toHaveCount(0) }) })