Files
wehub-resource-sync 7a0da7932b
Backwards Compatibility / Verify Encryption Constants (push) Waiting to run
Backwards Compatibility / PyPI Version Compatibility (push) Waiting to run
Backwards Compatibility / Database Migration Tests (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Blocked by required conditions
Docker Tests (Consolidated) / detect-changes (push) Waiting to run
Docker Tests (Consolidated) / Build Test Image (push) Waiting to run
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Blocked by required conditions
Docker Tests (Consolidated) / Accessibility Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Unit Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Example Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / Production Image Smoke Test (push) Blocked by required conditions
Docker Tests (Consolidated) / Infrastructure Tests (push) Blocked by required conditions
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Waiting to run
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

350 lines
16 KiB
JavaScript

/**
* 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 };