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
268 lines
9.1 KiB
JavaScript
268 lines
9.1 KiB
JavaScript
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');
|
||
}
|
||
}
|
||
})();
|