/** * Test for autocomplete selection behavior * Tests that clicking on autocomplete suggestions properly selects the item * for both LLM model and search engine dropdowns */ const puppeteer = require('puppeteer'); const AuthHelper = require('./auth_helper'); // Default timeout for tests const TEST_TIMEOUT = 30000; // Test configuration const config = { baseUrl: process.env.BASE_URL || 'http://127.0.0.1:5000', headless: process.env.HEADLESS !== 'false', slowMo: parseInt(process.env.SLOW_MO || '0', 10), devtools: process.env.DEVTOOLS === 'true' }; // Function to run tests when file is executed directly async function runTests() { let browser; let allTestsPassed = true; try { console.log('\n๐Ÿ“‹ Autocomplete Selection Tests\n'); console.log(`Configuration: headless=${config.headless}, baseUrl=${config.baseUrl}\n`); browser = await puppeteer.launch({ headless: config.headless, slowMo: config.slowMo, devtools: config.devtools, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-web-security', '--disable-features=IsolateOrigins,site-per-process' ] }); // Test 1: LLM model autocomplete selection console.log('๐Ÿงช Test 1: Should select LLM model from autocomplete when clicked'); try { const page = await browser.newPage(); await page.setViewport({ width: 1280, height: 800 }); const authHelper = new AuthHelper(page, config.baseUrl); page.setDefaultTimeout(TEST_TIMEOUT); await authHelper.ensureAuthenticated(); await page.goto(`${config.baseUrl}/`, { waitUntil: 'domcontentloaded' }); // Wait for and click the model input await page.waitForSelector('#model', { visible: true }); await page.click('#model'); // Wait for dropdown to appear await page.waitForSelector('#model-dropdown-list', { visible: true }); await page.waitForSelector('.ldr-custom-dropdown-item', { visible: true }); const dropdownItems = await page.$$('.ldr-custom-dropdown-item'); console.log(` Found ${dropdownItems.length} model options`); if (dropdownItems.length > 0) { // Get the first item's text const firstItemText = await page.evaluate(el => el.textContent, dropdownItems[0]); // Clear input and type part of the model name await page.evaluate(() => { document.getElementById('model').value = ''; }); const searchText = firstItemText.substring(0, Math.min(3, firstItemText.length)); await page.type('#model', searchText); console.log(` Typed "${searchText}" to filter models`); await new Promise(resolve => setTimeout(resolve, 500)); // Check if dropdown is still visible const dropdownVisible = await page.evaluate(() => { const dropdown = document.getElementById('model-dropdown-list'); return dropdown && window.getComputedStyle(dropdown).display !== 'none'; }); if (!dropdownVisible) { console.log(' Dropdown closed, reopening...'); await page.click('#model'); await page.waitForSelector('#model-dropdown-list', { visible: true }); } // Click the first filtered item const filteredItems = await page.$$('.ldr-custom-dropdown-item'); if (filteredItems.length > 0) { const itemToClick = await page.evaluate(el => el.textContent, filteredItems[0]); console.log(` Clicking on: "${itemToClick}"`); await filteredItems[0].click(); await new Promise(resolve => setTimeout(resolve, 500)); // Check the selected value const selectedModel = await page.evaluate(() => document.getElementById('model').value); const hiddenValue = await page.evaluate(() => { const hidden = document.getElementById('model_hidden'); return hidden ? hidden.value : null; }); console.log(` Display value: "${selectedModel}"`); console.log(` Hidden value: "${hiddenValue}"`); if (selectedModel && selectedModel !== searchText) { console.log(' โœ… Model autocomplete selection works correctly'); } else { console.log(' โŒ Model was not properly selected from autocomplete'); console.log(' Issue confirmed: Clicking autocomplete does not select the item'); allTestsPassed = false; } } else { console.log(' โš ๏ธ No filtered items found'); } } else { console.log(' โš ๏ธ No model options available'); } await page.close(); } catch (error) { console.error(` โŒ Test failed: ${error.message}`); allTestsPassed = false; } // Test 2: Search engine autocomplete selection console.log('\n๐Ÿงช Test 2: Should select search engine from autocomplete when clicked'); try { const page = await browser.newPage(); await page.setViewport({ width: 1280, height: 800 }); const authHelper = new AuthHelper(page, config.baseUrl); page.setDefaultTimeout(TEST_TIMEOUT); await authHelper.ensureAuthenticated(); await page.goto(`${config.baseUrl}/`, { waitUntil: 'domcontentloaded' }); // Wait for and click the search engine input await page.waitForSelector('#search_engine', { visible: true }); await page.click('#search_engine'); // Wait for dropdown to appear await page.waitForSelector('#search-engine-dropdown-list', { visible: true }); await page.waitForFunction(() => { const items = document.querySelectorAll('#search-engine-dropdown-list .ldr-custom-dropdown-item'); return items.length > 0; }); const dropdownItems = await page.$$('#search-engine-dropdown-list .ldr-custom-dropdown-item'); console.log(` Found ${dropdownItems.length} search engine options`); if (dropdownItems.length > 0) { // Get the first item's text const firstItemText = await page.evaluate(el => el.textContent, dropdownItems[0]); // Clear input and type part of the search engine name await page.evaluate(() => { document.getElementById('search_engine').value = ''; }); const searchText = firstItemText.substring(0, Math.min(3, firstItemText.length)); await page.type('#search_engine', searchText); console.log(` Typed "${searchText}" to filter search engines`); await new Promise(resolve => setTimeout(resolve, 500)); // Click the first filtered item const filteredItems = await page.$$('#search-engine-dropdown-list .ldr-custom-dropdown-item'); if (filteredItems.length > 0) { const itemToClick = await page.evaluate(el => el.textContent, filteredItems[0]); console.log(` Clicking on: "${itemToClick}"`); await filteredItems[0].click(); await new Promise(resolve => setTimeout(resolve, 500)); // Check the selected value const selectedEngine = await page.evaluate(() => document.getElementById('search_engine').value); const hiddenValue = await page.evaluate(() => { const hidden = document.getElementById('search_engine_hidden'); return hidden ? hidden.value : null; }); console.log(` Display value: "${selectedEngine}"`); console.log(` Hidden value: "${hiddenValue}"`); if (selectedEngine && selectedEngine !== searchText) { console.log(' โœ… Search engine autocomplete selection works correctly'); } else { console.log(' โŒ Search engine was not properly selected from autocomplete'); console.log(' Issue confirmed: Clicking autocomplete does not select the item'); allTestsPassed = false; } } else { console.log(' โš ๏ธ No filtered items found'); } } else { console.log(' โš ๏ธ No search engine options available'); } await page.close(); } catch (error) { console.error(` โŒ Test failed: ${error.message}`); allTestsPassed = false; } // Test 3: Keyboard navigation console.log('\n๐Ÿงช Test 3: Should verify keyboard navigation works for selection'); try { const page = await browser.newPage(); await page.setViewport({ width: 1280, height: 800 }); const authHelper = new AuthHelper(page, config.baseUrl); page.setDefaultTimeout(TEST_TIMEOUT); await authHelper.ensureAuthenticated(); await page.goto(`${config.baseUrl}/`, { waitUntil: 'domcontentloaded' }); // Test with model dropdown await page.waitForSelector('#model', { visible: true }); await page.click('#model'); await page.waitForSelector('#model-dropdown-list .ldr-custom-dropdown-item', { visible: true }); const itemCount = await page.evaluate(() => { return document.querySelectorAll('#model-dropdown-list .ldr-custom-dropdown-item').length; }); console.log(` Found ${itemCount} items in dropdown`); if (itemCount > 0) { // Use arrow key to navigate await page.keyboard.press('ArrowDown'); // Check if first item is highlighted const firstItemActive = await page.evaluate(() => { const items = document.querySelectorAll('#model-dropdown-list .ldr-custom-dropdown-item'); return items[0] && items[0].classList.contains('active'); }); console.log(` First item highlighted: ${firstItemActive}`); // Press Enter to select await page.keyboard.press('Enter'); await new Promise(resolve => setTimeout(resolve, 500)); // Check the selected value const selectedModel = await page.evaluate(() => document.getElementById('model').value); if (selectedModel) { console.log(` โœ… Keyboard navigation selected: "${selectedModel}"`); } else { console.log(' โŒ Keyboard navigation failed to select'); allTestsPassed = false; } } await page.close(); } catch (error) { console.error(` โŒ Test failed: ${error.message}`); allTestsPassed = false; } // Test 4: Type and Enter behavior (reveals the issue) console.log('\n๐Ÿงช Test 4: Type and immediate Enter (reveals the issue)'); try { const page = await browser.newPage(); await page.setViewport({ width: 1280, height: 800 }); const authHelper = new AuthHelper(page, config.baseUrl); page.setDefaultTimeout(TEST_TIMEOUT); await authHelper.ensureAuthenticated(); await page.goto(`${config.baseUrl}/`, { waitUntil: 'domcontentloaded' }); // Open model dropdown await page.waitForSelector('#model', { visible: true }); await page.click('#model'); await page.waitForSelector('#model-dropdown-list .ldr-custom-dropdown-item', { visible: true }); // Get a model name to type const firstModelText = await page.evaluate(() => { const firstItem = document.querySelector('#model-dropdown-list .ldr-custom-dropdown-item'); return firstItem ? firstItem.textContent : null; }); if (firstModelText) { // Clear and type part of the model name await page.evaluate(() => { document.getElementById('model').value = ''; }); const searchText = firstModelText.substring(0, Math.min(5, firstModelText.length)); await page.type('#model', searchText); console.log(` Typed "${searchText}"`); await new Promise(resolve => setTimeout(resolve, 300)); // Press Enter without using arrow keys await page.keyboard.press('Enter'); await new Promise(resolve => setTimeout(resolve, 500)); // Check what was selected const selectedValue = await page.evaluate(() => document.getElementById('model').value); if (selectedValue === searchText) { console.log(` โš ๏ธ Enter key only kept typed text: "${selectedValue}"`); console.log(' ๐Ÿ“ Issue confirmed: User must either:'); console.log(' - Click on the autocomplete suggestion'); console.log(' - Use arrow keys then Enter'); console.log(' - Typing and pressing Enter alone does NOT select from autocomplete'); } else { console.log(` โœ… Enter key selected from autocomplete: "${selectedValue}"`); } } await page.close(); } catch (error) { console.error(` โŒ Test failed: ${error.message}`); allTestsPassed = false; } } catch (error) { console.error(`\nโŒ Test suite failed: ${error.message}`); allTestsPassed = false; } finally { if (browser) { await browser.close(); } console.log('\n' + '='.repeat(60)); console.log('๐Ÿ“Š Test Summary:'); console.log(' - Model autocomplete: Tests if clicking selects the item'); console.log(' - Search engine autocomplete: Tests if clicking selects the item'); console.log(' - Keyboard navigation: Tests arrow key + Enter selection'); console.log(' - Type and Enter: Reveals if typing + Enter selects first match'); console.log('='.repeat(60)); if (allTestsPassed) { console.log('โœ… All tests completed successfully\n'); process.exit(0); } else { console.log('โŒ Some tests revealed issues with autocomplete selection\n'); console.log('The tests confirm that when typing in the autocomplete fields:'); console.log('1. The dropdown appears and filters correctly'); console.log('2. However, pressing Enter does not select the first match'); console.log('3. Users must either click or use arrow keys to select\n'); process.exit(1); } } } // Run tests if this file is executed directly if (require.main === module) { runTests().catch(error => { console.error('Fatal error:', error); process.exit(1); }); } module.exports = { runTests };