const puppeteer = require('puppeteer'); const path = require('path'); const { getPuppeteerLaunchOptions } = require('./puppeteer_config'); // Test configuration const BASE_URL = 'http://127.0.0.1:5000'; const TEST_USER = `settings_persist_${Date.now()}`; const TEST_PASSWORD = 'TestPass123!'; // Colors for console output const colors = { reset: '\x1b[0m', bright: '\x1b[1m', green: '\x1b[32m', red: '\x1b[31m', yellow: '\x1b[33m', blue: '\x1b[34m', cyan: '\x1b[36m' }; function log(message, type = 'info') { const timestamp = new Date().toISOString().split('T')[1].split('.')[0]; const typeColors = { 'info': colors.cyan, 'success': colors.green, 'error': colors.red, 'warning': colors.yellow, 'section': colors.blue }; const color = typeColors[type] || colors.reset; console.log(`${color}[${timestamp}] ${message}${colors.reset}`); } async function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function registerUser(page) { log('šŸ“ Registering new user...', 'info'); await page.goto(`${BASE_URL}/register`); await page.waitForSelector('#username'); await page.type('#username', TEST_USER); await page.type('#password', TEST_PASSWORD); await page.type('#password_confirm', TEST_PASSWORD); await page.click('button[type="submit"]'); await page.waitForNavigation(); log('āœ… Registration successful', 'success'); } async function loginUser(page) { log('šŸ” Logging in...', 'info'); await page.goto(`${BASE_URL}/login`); await page.waitForSelector('#username'); await page.type('#username', TEST_USER); await page.type('#password', TEST_PASSWORD); await page.click('button[type="submit"]'); await page.waitForNavigation(); log('āœ… Login successful', 'success'); } async function modifySettings(page) { log('\n=== MODIFYING SETTINGS ===', 'section'); await page.goto(`${BASE_URL}/settings`); await page.waitForSelector('.settings-form, #settings-form', { timeout: 10000 }); const testSettings = { // LLM settings temperature: 0.8, maxTokens: 2048, contextWindow: 8192, // Search settings iterations: 2, questionsPerIteration: 3, maxResults: 15, timeRange: '1y', // Report settings citationFormat: 'domain_hyperlinks' }; // Apply settings log('šŸ“ Applying test settings...', 'info'); // Temperature slider const tempSlider = await page.$('input[name="llm.temperature"], #temperature-slider'); if (tempSlider) { await page.evaluate((value) => { const slider = document.querySelector('input[name="llm.temperature"], #temperature-slider'); if (slider) { slider.value = value; slider.dispatchEvent(new Event('change', { bubbles: true })); } }, testSettings.temperature); log(` - Temperature set to: ${testSettings.temperature}`, 'info'); } // Max tokens const maxTokensInput = await page.$('input[name="llm.max_tokens"], #max-tokens'); if (maxTokensInput) { await page.evaluate((el) => { el.value = ''; }, maxTokensInput); await page.type('input[name="llm.max_tokens"], #max-tokens', testSettings.maxTokens.toString()); log(` - Max tokens set to: ${testSettings.maxTokens}`, 'info'); } // Search iterations const iterationsInput = await page.$('input[name="search.iterations"], #search-iterations'); if (iterationsInput) { await page.evaluate((el) => { el.value = ''; }, iterationsInput); await page.type('input[name="search.iterations"], #search-iterations', testSettings.iterations.toString()); log(` - Search iterations set to: ${testSettings.iterations}`, 'info'); } // Questions per iteration const questionsInput = await page.$('input[name="search.questions_per_iteration"], #questions-per-iteration'); if (questionsInput) { await page.evaluate((el) => { el.value = ''; }, questionsInput); await page.type('input[name="search.questions_per_iteration"], #questions-per-iteration', testSettings.questionsPerIteration.toString()); log(` - Questions per iteration set to: ${testSettings.questionsPerIteration}`, 'info'); } // Citation format dropdown const citationSelect = await page.$('select[name="report.citation_format"], #citation-format'); if (citationSelect) { await page.select('select[name="report.citation_format"], #citation-format', testSettings.citationFormat); log(` - Citation format set to: ${testSettings.citationFormat}`, 'info'); } // Save settings log('šŸ’¾ Saving settings...', 'info'); const saveButton = await page.$('button[type="submit"], .save-settings-btn, #save-settings'); if (saveButton) { await saveButton.click(); await delay(2000); // Wait for save // Check for success message const successMessage = await page.$('.alert-success, .success-message'); if (successMessage) { log('āœ… Settings saved successfully', 'success'); } } // Capture current settings const currentSettings = await page.evaluate(() => { const settings = {}; // Get all input values const inputs = document.querySelectorAll('input[name], select[name], textarea[name]'); inputs.forEach(input => { if (input.type === 'checkbox') { settings[input.name] = input.checked; } else { settings[input.name] = input.value; } }); return settings; }); return { testSettings, currentSettings }; } async function verifySettingsPersistence(page, originalSettings) { log('\n=== VERIFYING SETTINGS PERSISTENCE ===', 'section'); await page.goto(`${BASE_URL}/settings`); await page.waitForSelector('.settings-form, #settings-form', { timeout: 10000 }); // Wait for settings to load await delay(2000); // Get current settings const persistedSettings = await page.evaluate(() => { const settings = {}; // Temperature const tempSlider = document.querySelector('input[name="llm.temperature"], #temperature-slider'); if (tempSlider) settings.temperature = parseFloat(tempSlider.value); // Max tokens const maxTokens = document.querySelector('input[name="llm.max_tokens"], #max-tokens'); if (maxTokens) settings.maxTokens = parseInt(maxTokens.value, 10); // Iterations const iterations = document.querySelector('input[name="search.iterations"], #search-iterations'); if (iterations) settings.iterations = parseInt(iterations.value, 10); // Questions per iteration const questions = document.querySelector('input[name="search.questions_per_iteration"], #questions-per-iteration'); if (questions) settings.questionsPerIteration = parseInt(questions.value, 10); // Citation format const citation = document.querySelector('select[name="report.citation_format"], #citation-format'); if (citation) settings.citationFormat = citation.value; return settings; }); // Compare settings log('šŸ” Comparing settings...', 'info'); let allMatch = true; Object.keys(originalSettings.testSettings).forEach(key => { const original = originalSettings.testSettings[key]; const persisted = persistedSettings[key]; if (original !== persisted) { log(` āŒ ${key}: Expected ${original}, got ${persisted}`, 'error'); allMatch = false; } else { log(` āœ… ${key}: ${persisted} (matches)`, 'success'); } }); return allMatch; } async function testSettingsPersistence() { const browser = await puppeteer.launch(getPuppeteerLaunchOptions()); const page = await browser.newPage(); // Set console log handler page.on('console', msg => { if (msg.type() === 'error' && !msg.text().includes('favicon')) { log(`Browser console error: ${msg.text()}`, 'error'); } }); try { // Step 1: Register and modify settings await registerUser(page); const settingsData = await modifySettings(page); // Step 2: Logout log('\n=== LOGGING OUT ===', 'section'); await page.goto(`${BASE_URL}/logout`); await delay(1000); log('āœ… Logged out', 'success'); // Step 3: Login again await loginUser(page); // Step 4: Verify settings persisted const settingsMatch = await verifySettingsPersistence(page, settingsData); if (settingsMatch) { log('\nāœ… All settings persisted correctly!', 'success'); } else { throw new Error('Some settings did not persist correctly'); } // Test settings on research page log('\n=== VERIFYING SETTINGS APPLY TO RESEARCH ===', 'section'); await page.goto(`${BASE_URL}/research`); await page.waitForSelector('#research-form, .research-form'); // Check if settings are reflected in research form const researchFormSettings = await page.evaluate(() => { const settings = {}; // Check hidden inputs or data attributes const modelInput = document.querySelector('input[name="model"], #model'); if (modelInput) settings.model = modelInput.value; const iterationsDisplay = document.querySelector('.iterations-display, [data-iterations]'); if (iterationsDisplay) { settings.displayedIterations = iterationsDisplay.textContent || iterationsDisplay.getAttribute('data-iterations'); } return settings; }); log('šŸ“Š Research form reflects settings', 'info'); // Test settings reset log('\n=== TESTING SETTINGS RESET ===', 'section'); await page.goto(`${BASE_URL}/settings`); const resetButton = await page.$('.reset-settings-btn, button[data-action="reset"]'); if (resetButton) { await resetButton.click(); // Handle confirmation dialog page.on('dialog', async dialog => { await dialog.accept(); }); await delay(2000); // Verify some settings returned to defaults const afterReset = await page.evaluate(() => { const temp = document.querySelector('input[name="llm.temperature"], #temperature-slider'); return temp ? parseFloat(temp.value) : null; }); if (afterReset !== null && afterReset !== settingsData.testSettings.temperature) { log('āœ… Reset functionality works', 'success'); } } // Capture final screenshot await page.screenshot({ path: path.join(__dirname, 'screenshots', 'settings_persistence_final.png'), fullPage: true }); log('\nāœ… Settings persistence test completed successfully!', 'success'); } catch (error) { log(`\nāŒ Test failed: ${error.message}`, 'error'); // Capture error screenshot await page.screenshot({ path: path.join(__dirname, 'screenshots', 'settings_persistence_error.png'), fullPage: true }); throw error; } finally { await browser.close(); } } // Run the test testSettingsPersistence().catch(error => { console.error('Test execution failed:', error); process.exit(1); });