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
340 lines
12 KiB
JavaScript
340 lines
12 KiB
JavaScript
const puppeteer = require('puppeteer');
|
|
const path = require('path');
|
|
const { getPuppeteerLaunchOptions } = require('./puppeteer_config');
|
|
|
|
// Test configuration
|
|
const BASE_URL = 'http://127.0.0.1:5000';
|
|
const TEST_USER = `settings_persist_${Date.now()}`;
|
|
const TEST_PASSWORD = 'TestPass123!';
|
|
|
|
// Colors for console output
|
|
const colors = {
|
|
reset: '\x1b[0m',
|
|
bright: '\x1b[1m',
|
|
green: '\x1b[32m',
|
|
red: '\x1b[31m',
|
|
yellow: '\x1b[33m',
|
|
blue: '\x1b[34m',
|
|
cyan: '\x1b[36m'
|
|
};
|
|
|
|
function log(message, type = 'info') {
|
|
const timestamp = new Date().toISOString().split('T')[1].split('.')[0];
|
|
const typeColors = {
|
|
'info': colors.cyan,
|
|
'success': colors.green,
|
|
'error': colors.red,
|
|
'warning': colors.yellow,
|
|
'section': colors.blue
|
|
};
|
|
const color = typeColors[type] || colors.reset;
|
|
console.log(`${color}[${timestamp}] ${message}${colors.reset}`);
|
|
}
|
|
|
|
async function delay(ms) {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
async function registerUser(page) {
|
|
log('📝 Registering new user...', 'info');
|
|
|
|
await page.goto(`${BASE_URL}/register`);
|
|
await page.waitForSelector('#username');
|
|
|
|
await page.type('#username', TEST_USER);
|
|
await page.type('#password', TEST_PASSWORD);
|
|
await page.type('#password_confirm', TEST_PASSWORD);
|
|
|
|
await page.click('button[type="submit"]');
|
|
await page.waitForNavigation();
|
|
|
|
log('✅ Registration successful', 'success');
|
|
}
|
|
|
|
async function loginUser(page) {
|
|
log('🔐 Logging in...', 'info');
|
|
|
|
await page.goto(`${BASE_URL}/login`);
|
|
await page.waitForSelector('#username');
|
|
|
|
await page.type('#username', TEST_USER);
|
|
await page.type('#password', TEST_PASSWORD);
|
|
|
|
await page.click('button[type="submit"]');
|
|
await page.waitForNavigation();
|
|
|
|
log('✅ Login successful', 'success');
|
|
}
|
|
|
|
async function modifySettings(page) {
|
|
log('\n=== MODIFYING SETTINGS ===', 'section');
|
|
|
|
await page.goto(`${BASE_URL}/settings`);
|
|
await page.waitForSelector('.settings-form, #settings-form', { timeout: 10000 });
|
|
|
|
const testSettings = {
|
|
// LLM settings
|
|
temperature: 0.8,
|
|
maxTokens: 2048,
|
|
contextWindow: 8192,
|
|
|
|
// Search settings
|
|
iterations: 2,
|
|
questionsPerIteration: 3,
|
|
maxResults: 15,
|
|
timeRange: '1y',
|
|
|
|
// Report settings
|
|
citationFormat: 'domain_hyperlinks'
|
|
};
|
|
|
|
// Apply settings
|
|
log('📝 Applying test settings...', 'info');
|
|
|
|
// Temperature slider
|
|
const tempSlider = await page.$('input[name="llm.temperature"], #temperature-slider');
|
|
if (tempSlider) {
|
|
await page.evaluate((value) => {
|
|
const slider = document.querySelector('input[name="llm.temperature"], #temperature-slider');
|
|
if (slider) {
|
|
slider.value = value;
|
|
slider.dispatchEvent(new Event('change', { bubbles: true }));
|
|
}
|
|
}, testSettings.temperature);
|
|
log(` - Temperature set to: ${testSettings.temperature}`, 'info');
|
|
}
|
|
|
|
// Max tokens
|
|
const maxTokensInput = await page.$('input[name="llm.max_tokens"], #max-tokens');
|
|
if (maxTokensInput) {
|
|
await page.evaluate((el) => { el.value = ''; }, maxTokensInput);
|
|
await page.type('input[name="llm.max_tokens"], #max-tokens', testSettings.maxTokens.toString());
|
|
log(` - Max tokens set to: ${testSettings.maxTokens}`, 'info');
|
|
}
|
|
|
|
// Search iterations
|
|
const iterationsInput = await page.$('input[name="search.iterations"], #search-iterations');
|
|
if (iterationsInput) {
|
|
await page.evaluate((el) => { el.value = ''; }, iterationsInput);
|
|
await page.type('input[name="search.iterations"], #search-iterations', testSettings.iterations.toString());
|
|
log(` - Search iterations set to: ${testSettings.iterations}`, 'info');
|
|
}
|
|
|
|
// Questions per iteration
|
|
const questionsInput = await page.$('input[name="search.questions_per_iteration"], #questions-per-iteration');
|
|
if (questionsInput) {
|
|
await page.evaluate((el) => { el.value = ''; }, questionsInput);
|
|
await page.type('input[name="search.questions_per_iteration"], #questions-per-iteration', testSettings.questionsPerIteration.toString());
|
|
log(` - Questions per iteration set to: ${testSettings.questionsPerIteration}`, 'info');
|
|
}
|
|
|
|
// Citation format dropdown
|
|
const citationSelect = await page.$('select[name="report.citation_format"], #citation-format');
|
|
if (citationSelect) {
|
|
await page.select('select[name="report.citation_format"], #citation-format', testSettings.citationFormat);
|
|
log(` - Citation format set to: ${testSettings.citationFormat}`, 'info');
|
|
}
|
|
|
|
// Save settings
|
|
log('💾 Saving settings...', 'info');
|
|
const saveButton = await page.$('button[type="submit"], .save-settings-btn, #save-settings');
|
|
if (saveButton) {
|
|
await saveButton.click();
|
|
await delay(2000); // Wait for save
|
|
|
|
// Check for success message
|
|
const successMessage = await page.$('.alert-success, .success-message');
|
|
if (successMessage) {
|
|
log('✅ Settings saved successfully', 'success');
|
|
}
|
|
}
|
|
|
|
// Capture current settings
|
|
const currentSettings = await page.evaluate(() => {
|
|
const settings = {};
|
|
|
|
// Get all input values
|
|
const inputs = document.querySelectorAll('input[name], select[name], textarea[name]');
|
|
inputs.forEach(input => {
|
|
if (input.type === 'checkbox') {
|
|
settings[input.name] = input.checked;
|
|
} else {
|
|
settings[input.name] = input.value;
|
|
}
|
|
});
|
|
|
|
return settings;
|
|
});
|
|
|
|
return { testSettings, currentSettings };
|
|
}
|
|
|
|
async function verifySettingsPersistence(page, originalSettings) {
|
|
log('\n=== VERIFYING SETTINGS PERSISTENCE ===', 'section');
|
|
|
|
await page.goto(`${BASE_URL}/settings`);
|
|
await page.waitForSelector('.settings-form, #settings-form', { timeout: 10000 });
|
|
|
|
// Wait for settings to load
|
|
await delay(2000);
|
|
|
|
// Get current settings
|
|
const persistedSettings = await page.evaluate(() => {
|
|
const settings = {};
|
|
|
|
// Temperature
|
|
const tempSlider = document.querySelector('input[name="llm.temperature"], #temperature-slider');
|
|
if (tempSlider) settings.temperature = parseFloat(tempSlider.value);
|
|
|
|
// Max tokens
|
|
const maxTokens = document.querySelector('input[name="llm.max_tokens"], #max-tokens');
|
|
if (maxTokens) settings.maxTokens = parseInt(maxTokens.value, 10);
|
|
|
|
// Iterations
|
|
const iterations = document.querySelector('input[name="search.iterations"], #search-iterations');
|
|
if (iterations) settings.iterations = parseInt(iterations.value, 10);
|
|
|
|
// Questions per iteration
|
|
const questions = document.querySelector('input[name="search.questions_per_iteration"], #questions-per-iteration');
|
|
if (questions) settings.questionsPerIteration = parseInt(questions.value, 10);
|
|
|
|
// Citation format
|
|
const citation = document.querySelector('select[name="report.citation_format"], #citation-format');
|
|
if (citation) settings.citationFormat = citation.value;
|
|
|
|
return settings;
|
|
});
|
|
|
|
// Compare settings
|
|
log('🔍 Comparing settings...', 'info');
|
|
let allMatch = true;
|
|
|
|
Object.keys(originalSettings.testSettings).forEach(key => {
|
|
const original = originalSettings.testSettings[key];
|
|
const persisted = persistedSettings[key];
|
|
|
|
if (original !== persisted) {
|
|
log(` ❌ ${key}: Expected ${original}, got ${persisted}`, 'error');
|
|
allMatch = false;
|
|
} else {
|
|
log(` ✅ ${key}: ${persisted} (matches)`, 'success');
|
|
}
|
|
});
|
|
|
|
return allMatch;
|
|
}
|
|
|
|
async function testSettingsPersistence() {
|
|
const browser = await puppeteer.launch(getPuppeteerLaunchOptions());
|
|
|
|
const page = await browser.newPage();
|
|
|
|
// Set console log handler
|
|
page.on('console', msg => {
|
|
if (msg.type() === 'error' && !msg.text().includes('favicon')) {
|
|
log(`Browser console error: ${msg.text()}`, 'error');
|
|
}
|
|
});
|
|
|
|
try {
|
|
// Step 1: Register and modify settings
|
|
await registerUser(page);
|
|
const settingsData = await modifySettings(page);
|
|
|
|
// Step 2: Logout
|
|
log('\n=== LOGGING OUT ===', 'section');
|
|
await page.goto(`${BASE_URL}/logout`);
|
|
await delay(1000);
|
|
log('✅ Logged out', 'success');
|
|
|
|
// Step 3: Login again
|
|
await loginUser(page);
|
|
|
|
// Step 4: Verify settings persisted
|
|
const settingsMatch = await verifySettingsPersistence(page, settingsData);
|
|
|
|
if (settingsMatch) {
|
|
log('\n✅ All settings persisted correctly!', 'success');
|
|
} else {
|
|
throw new Error('Some settings did not persist correctly');
|
|
}
|
|
|
|
// Test settings on research page
|
|
log('\n=== VERIFYING SETTINGS APPLY TO RESEARCH ===', 'section');
|
|
await page.goto(`${BASE_URL}/research`);
|
|
await page.waitForSelector('#research-form, .research-form');
|
|
|
|
// Check if settings are reflected in research form
|
|
const researchFormSettings = await page.evaluate(() => {
|
|
const settings = {};
|
|
|
|
// Check hidden inputs or data attributes
|
|
const modelInput = document.querySelector('input[name="model"], #model');
|
|
if (modelInput) settings.model = modelInput.value;
|
|
|
|
const iterationsDisplay = document.querySelector('.iterations-display, [data-iterations]');
|
|
if (iterationsDisplay) {
|
|
settings.displayedIterations = iterationsDisplay.textContent ||
|
|
iterationsDisplay.getAttribute('data-iterations');
|
|
}
|
|
|
|
return settings;
|
|
});
|
|
|
|
log('📊 Research form reflects settings', 'info');
|
|
|
|
// Test settings reset
|
|
log('\n=== TESTING SETTINGS RESET ===', 'section');
|
|
await page.goto(`${BASE_URL}/settings`);
|
|
|
|
const resetButton = await page.$('.reset-settings-btn, button[data-action="reset"]');
|
|
if (resetButton) {
|
|
await resetButton.click();
|
|
|
|
// Handle confirmation dialog
|
|
page.on('dialog', async dialog => {
|
|
await dialog.accept();
|
|
});
|
|
|
|
await delay(2000);
|
|
|
|
// Verify some settings returned to defaults
|
|
const afterReset = await page.evaluate(() => {
|
|
const temp = document.querySelector('input[name="llm.temperature"], #temperature-slider');
|
|
return temp ? parseFloat(temp.value) : null;
|
|
});
|
|
|
|
if (afterReset !== null && afterReset !== settingsData.testSettings.temperature) {
|
|
log('✅ Reset functionality works', 'success');
|
|
}
|
|
}
|
|
|
|
// Capture final screenshot
|
|
await page.screenshot({
|
|
path: path.join(__dirname, 'screenshots', 'settings_persistence_final.png'),
|
|
fullPage: true
|
|
});
|
|
|
|
log('\n✅ Settings persistence test completed successfully!', 'success');
|
|
|
|
} catch (error) {
|
|
log(`\n❌ Test failed: ${error.message}`, 'error');
|
|
|
|
// Capture error screenshot
|
|
await page.screenshot({
|
|
path: path.join(__dirname, 'screenshots', 'settings_persistence_error.png'),
|
|
fullPage: true
|
|
});
|
|
|
|
throw error;
|
|
} finally {
|
|
await browser.close();
|
|
}
|
|
}
|
|
|
|
// Run the test
|
|
testSettingsPersistence().catch(error => {
|
|
console.error('Test execution failed:', error);
|
|
process.exit(1);
|
|
});
|