chore: import upstream snapshot with attribution
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
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:08:55 +08:00
commit 7a0da7932b
2985 changed files with 1049377 additions and 0 deletions
+267
View File
@@ -0,0 +1,267 @@
const puppeteer = require('puppeteer');
const AuthHelper = require('./auth_helper');
const { getPuppeteerLaunchOptions } = require('./puppeteer_config');
// Color codes for terminal output
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m'
};
function log(message, type = 'info') {
const timestamp = new Date().toISOString();
const prefix = {
info: `${colors.blue}`,
success: `${colors.green}`,
error: `${colors.red}ERROR:`,
warn: `${colors.yellow}`
}[type] || '';
console.log(`${prefix}[${timestamp}] ${message}${colors.reset}`);
}
(async () => {
let browser;
let authHelper;
try {
// Test configuration
const TEST_API_KEY_1 = 'enter-save-test-key-12345';
const TEST_API_KEY_2 = 'enter-save-changed-67890';
const BASE_URL = 'http://localhost:5000';
log(`${colors.bright}=== Testing API Key Save with Enter Key ===${colors.reset}`, 'info');
// Launch browser
browser = await puppeteer.launch(getPuppeteerLaunchOptions());
log('Browser launched in visible mode', 'success');
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080 });
// Log browser console errors
page.on('console', msg => {
if (msg.type() === 'error') {
log(`Browser console: ${msg.text()}`, 'error');
}
});
// Listen for page dialogs (alerts, confirms)
page.on('dialog', async dialog => {
log(`Dialog appeared: ${dialog.message()}`, 'warn');
await dialog.accept();
});
// Initialize auth helper
authHelper = new AuthHelper(page);
// Create test user
const timestamp = Date.now();
const testUsername = `enter_test_${timestamp}`;
const testPassword = 'testpass123';
log(`Creating user: ${testUsername}`, 'info');
// Register and login
await authHelper.register(testUsername, testPassword);
const isAuthenticated = await authHelper.isLoggedIn();
if (!isAuthenticated) {
throw new Error('Failed to authenticate after registration');
}
log('User authenticated successfully', 'success');
// Navigate to settings page
log('Navigating to settings page...', 'info');
await page.goto(`${BASE_URL}/settings`, { waitUntil: 'domcontentloaded' });
// Wait a bit for page to fully load
await new Promise(resolve => setTimeout(resolve, 2000));
// Take initial screenshot
await page.screenshot({
path: `/tmp/enter_key_test_initial_${timestamp}.png`,
fullPage: false
});
log('Screenshot saved: Initial settings page', 'info');
// Find the API key input field
log('Looking for OpenAI Endpoint API key field...', 'info');
const apiKeySelectors = [
'input[name="llm.openai_endpoint.api_key"]',
'input[id="llm.openai_endpoint.api_key"]',
'input[data-setting="llm.openai_endpoint.api_key"]',
'#llm\\.openai_endpoint\\.api_key'
];
let apiKeyInput = null;
for (const selector of apiKeySelectors) {
try {
apiKeyInput = await page.$(selector);
if (apiKeyInput) {
log(`Found API key input with selector: ${selector}`, 'success');
break;
}
} catch {
// Continue with next selector
}
}
if (!apiKeyInput) {
throw new Error('Could not find OpenAI Endpoint API key input field');
}
// Scroll the input into view
await apiKeyInput.evaluate(el => el.scrollIntoView({ behavior: 'smooth', block: 'center' }));
await new Promise(resolve => setTimeout(resolve, 500));
// Clear any existing value and type the first API key
log(`Clearing field and typing API key: ${TEST_API_KEY_1}`, 'info');
await apiKeyInput.click({ clickCount: 3 });
await page.keyboard.press('Backspace');
await apiKeyInput.type(TEST_API_KEY_1);
// Take screenshot before pressing Enter
await page.screenshot({
path: `/tmp/enter_key_test_before_enter_${timestamp}.png`,
fullPage: false
});
log('Screenshot saved: Before pressing Enter', 'info');
// Press Enter to save
log('Pressing Enter to save...', 'info');
await page.keyboard.press('Enter');
// Wait for any save operation to complete
await new Promise(resolve => setTimeout(resolve, 2000));
// Take screenshot after Enter
await page.screenshot({
path: `/tmp/enter_key_test_after_enter_${timestamp}.png`,
fullPage: false
});
log('Screenshot saved: After pressing Enter', 'info');
// Check for any success messages or indicators
const successIndicators = [
'.alert-success',
'.success-message',
'[class*="success"]',
'.saved-indicator',
'.toast-success'
];
let successFound = false;
for (const selector of successIndicators) {
const element = await page.$(selector);
if (element) {
const text = await element.evaluate(el => el.textContent);
log(`Success indicator found: ${text}`, 'success');
successFound = true;
break;
}
}
// Check if the value persisted by reloading
log('Reloading page to check persistence...', 'info');
await page.reload({ waitUntil: 'domcontentloaded' });
await new Promise(resolve => setTimeout(resolve, 2000));
// Find the input again
apiKeyInput = null;
for (const selector of apiKeySelectors) {
apiKeyInput = await page.$(selector);
if (apiKeyInput) break;
}
if (apiKeyInput) {
const currentValue = await apiKeyInput.evaluate(el => el.value);
log(`Value after reload: ${currentValue ? '***' + currentValue.slice(-5) : 'empty'}`, 'info');
// Now try the second API key
log(`Trying second API key: ${TEST_API_KEY_2}`, 'info');
await apiKeyInput.click({ clickCount: 3 });
await page.keyboard.press('Backspace');
await apiKeyInput.type(TEST_API_KEY_2);
// Try different save methods
log('Testing different save triggers...', 'info');
// Method 1: Press Enter
log('Method 1: Pressing Enter', 'info');
await page.keyboard.press('Enter');
await new Promise(resolve => setTimeout(resolve, 1000));
// Method 2: Tab away (blur event)
log('Method 2: Tabbing away from field', 'info');
await page.keyboard.press('Tab');
await new Promise(resolve => setTimeout(resolve, 1000));
// Method 3: Click elsewhere
log('Method 3: Clicking elsewhere on page', 'info');
await page.click('body');
await new Promise(resolve => setTimeout(resolve, 1000));
}
// Check if there's a form around the input
const formInfo = await page.evaluate(() => {
const input = document.querySelector('input[name="llm.openai_endpoint.api_key"]');
if (!input) return null;
const form = input.closest('form');
return {
hasForm: !!form,
formAction: form?.action,
formMethod: form?.method,
inputType: input.type,
hasOnChange: !!input.onchange,
hasOnKeyPress: !!input.onkeypress,
dataAttributes: Object.keys(input.dataset || {})
};
});
log(`Form analysis: ${JSON.stringify(formInfo, null, 2)}`, 'info');
// Final screenshot
await page.screenshot({
path: `/tmp/enter_key_test_final_${timestamp}.png`,
fullPage: false
});
log('Screenshot saved: Final state', 'info');
log('Test completed - check screenshots to see results', 'success');
log('Note: Browser is left open for manual inspection', 'info');
// Keep browser open for manual inspection
log('Browser will remain open for 30 seconds...', 'info');
await new Promise(resolve => setTimeout(resolve, 30000));
} catch (error) {
log(`Test failed: ${error.message}`, 'error');
console.error(error);
// Take error screenshot
if (browser) {
const page = (await browser.pages())[0];
if (page) {
await page.screenshot({
path: `/tmp/enter_key_test_error_${Date.now()}.png`,
fullPage: false
});
log('Error screenshot saved', 'info');
}
}
process.exit(1);
} finally {
if (browser) {
await browser.close();
log('Browser closed', 'success');
}
}
})();