Files
wehub-resource-sync 7a0da7932b
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
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

268 lines
9.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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');
}
}
})();