/** * UI Tests for Library Document Management * Tests document viewing, searching, and management in the Library. */ const puppeteer = require('puppeteer'); const AuthHelper = require('../auth_helper'); const { getPuppeteerLaunchOptions } = require('../puppeteer_config'); const BASE_URL = process.env.TEST_BASE_URL || 'http://127.0.0.1:5000'; const TIMEOUT = 30000; // Helper function for delays (Puppeteer doesn't have waitForTimeout like Playwright) const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)); describe('Library Documents UI Tests', () => { let browser; let page; let authHelper; beforeAll(async () => { browser = await puppeteer.launch(getPuppeteerLaunchOptions()); }); afterAll(async () => { if (browser) { await browser.close(); } }); beforeEach(async () => { page = await browser.newPage(); page.setDefaultTimeout(TIMEOUT); authHelper = new AuthHelper(page, BASE_URL); // Authenticate before each test await page.goto(BASE_URL, { waitUntil: 'domcontentloaded' }); await authHelper.ensureAuthenticated(); }); afterEach(async () => { if (page) { await page.close(); } }); describe('Library Page Load', () => { test('should load library page', async () => { await page.goto(`${BASE_URL}/library/`, { waitUntil: 'domcontentloaded' }); const pageTitle = await page.title(); expect(pageTitle.toLowerCase()).toContain('library'); }); test('should display navigation elements', async () => { await page.goto(`${BASE_URL}/library/`, { waitUntil: 'domcontentloaded' }); // Check for main navigation elements const mainNav = await page.$('nav, .navbar, .sidebar'); expect(mainNav).toBeTruthy(); // Check for library-specific navigation const libraryNav = await page.$('.library-nav, .collection-sidebar, [role="navigation"]'); // Library nav is optional but page should load const pageContent = await page.content(); expect(pageContent.length).toBeGreaterThan(0); }); test('should show search functionality', async () => { await page.goto(`${BASE_URL}/library/`, { waitUntil: 'domcontentloaded' }); // Look for search input const searchInput = await page.$( 'input[type="search"], input[name="query"], .search-input, #library-search' ); // Search should be available expect(searchInput).toBeTruthy(); }); }); describe('Document Search', () => { test('should allow entering search query', async () => { await page.goto(`${BASE_URL}/library/`, { waitUntil: 'domcontentloaded' }); const searchInput = await page.$( 'input[type="search"], input[name="query"], .search-input' ); if (searchInput) { await searchInput.type('test query'); const inputValue = await page.$eval( 'input[type="search"], input[name="query"], .search-input', el => el.value ); expect(inputValue).toBe('test query'); } }); test('should submit search form', async () => { await page.goto(`${BASE_URL}/library/`, { waitUntil: 'domcontentloaded' }); const searchInput = await page.$( 'input[type="search"], input[name="query"], .search-input' ); if (searchInput) { await searchInput.type('machine learning'); // Submit search await page.keyboard.press('Enter'); // Wait for results or loading state await delay(2000); // Check for results or empty state const pageContent = await page.content(); const hasResults = pageContent.includes('result') || pageContent.includes('document') || pageContent.includes('No results'); expect(hasResults).toBeTruthy(); } }); }); describe('Document Viewer', () => { test('should open document when clicked', async () => { await page.goto(`${BASE_URL}/library/`, { waitUntil: 'domcontentloaded' }); // Look for a document link const documentLink = await page.$( '.document-item a, [data-document-id], .doc-title' ); if (documentLink) { const initialUrl = page.url(); await documentLink.click(); await delay(1000); const newUrl = page.url(); // URL should change or modal should open const urlChanged = newUrl !== initialUrl; const modalOpened = await page.$('.modal.show, .document-viewer'); expect(urlChanged || modalOpened).toBeTruthy(); } }); test('should display document content', async () => { // Navigate to a specific document if available await page.goto(`${BASE_URL}/library/`, { waitUntil: 'domcontentloaded' }); const documentLink = await page.$( '.document-item a, [data-document-id]' ); if (documentLink) { await documentLink.click(); await delay(2000); // Look for document content area const contentArea = await page.$( '.document-content, .doc-viewer, .pdf-viewer, .text-content' ); // Content area should exist if document was opened const pageContent = await page.content(); expect(pageContent.length).toBeGreaterThan(0); } }); }); describe('Document Actions', () => { test('should show document action menu', async () => { await page.goto(`${BASE_URL}/library/`, { waitUntil: 'domcontentloaded' }); // Look for action menu button const actionButton = await page.$( '.doc-actions, .dropdown-toggle, [data-action="more"]' ); if (actionButton) { await actionButton.click(); // Menu should appear const menu = await page.$('.dropdown-menu.show, .action-menu'); expect(menu).toBeTruthy(); } }); test('should allow document deletion', async () => { await page.goto(`${BASE_URL}/library/`, { waitUntil: 'domcontentloaded' }); // Look for delete option const deleteButton = await page.$( 'button[data-action="delete-doc"], .delete-doc-btn' ); if (deleteButton) { await deleteButton.click(); // Should show confirmation const confirmDialog = await page.$('.confirm-dialog, .modal-confirm'); expect(confirmDialog).toBeTruthy(); } }); }); describe('RAG Integration', () => { test('should show RAG search option', async () => { await page.goto(`${BASE_URL}/library/`, { waitUntil: 'domcontentloaded' }); // Look for RAG/semantic search option const ragOption = await page.$( '.rag-search, [data-action="semantic-search"], .ai-search' ); // RAG search may be available const pageContent = await page.content(); const hasRagFeature = ragOption !== null || pageContent.includes('semantic') || pageContent.includes('AI search') || pageContent.includes('RAG'); // Just verify page loaded expect(pageContent.length).toBeGreaterThan(0); }); test('should show index status', async () => { await page.goto(`${BASE_URL}/library/`, { waitUntil: 'domcontentloaded' }); // Look for index status indicator const indexStatus = await page.$( '.index-status, [data-testid="rag-status"], .embedding-status' ); // Status may or may not be visible const pageContent = await page.content(); expect(pageContent.length).toBeGreaterThan(0); }); }); describe('Download Manager', () => { test('should show download queue link', async () => { await page.goto(`${BASE_URL}/library/`, { waitUntil: 'domcontentloaded' }); // Look for download queue link const downloadQueueLink = await page.$( 'a[href*="downloads"], .download-queue-link' ); const pageContent = await page.content(); const hasDownloadFeature = downloadQueueLink !== null || pageContent.includes('download') || pageContent.includes('queue'); expect(pageContent.length).toBeGreaterThan(0); }); test('should open download queue page', async () => { // Navigate directly to downloads page await page.goto(`${BASE_URL}/library/downloads`, { waitUntil: 'domcontentloaded' }); const pageTitle = await page.title(); const pageContent = await page.content(); // Should load without error expect(pageContent.length).toBeGreaterThan(0); }); }); }); // Run tests if (require.main === module) { const { execSync } = require('child_process'); try { execSync(`npx jest ${__filename} --testTimeout=60000`, { stdio: 'inherit' }); } catch { process.exit(1); } }