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
201 lines
8.0 KiB
JavaScript
201 lines
8.0 KiB
JavaScript
/**
|
|
* Research Submit Test
|
|
* Tests the research form submission workflow
|
|
* CI-compatible: Works in both local and CI environments
|
|
*/
|
|
|
|
const puppeteer = require('puppeteer');
|
|
const AuthHelper = require('./auth_helper');
|
|
const { CI_TEST_USER } = require('./auth_helper');
|
|
const { getPuppeteerLaunchOptions } = require('./puppeteer_config');
|
|
const { setupDefaultModel } = require('./model_helper');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// NAVIGATION NOTE: Using 'domcontentloaded' instead of 'networkidle2' for page.goto()
|
|
// because networkidle2 waits for no network activity for 500ms, but WebSocket
|
|
// connections and background polling keep the network active, causing infinite hangs.
|
|
// See: test_login_validation.js and auth_helper.js for detailed explanation.
|
|
(async () => {
|
|
let browser;
|
|
const isCI = !!process.env.CI;
|
|
|
|
// Skip in CI: setupDefaultModel() triggers provider-change JS that clears the
|
|
// query field, causing the form to submit empty and redirect to /. This is a
|
|
// test-infrastructure issue, not a product bug.
|
|
if (isCI) {
|
|
console.log('⏭️ Skipping research submit test in CI (known model-setup race condition)');
|
|
process.exit(0);
|
|
}
|
|
|
|
console.log(`🧪 Running research submit test (CI mode: ${isCI})`);
|
|
// Create screenshots directory
|
|
const screenshotsDir = path.join(__dirname, 'screenshots');
|
|
if (!fs.existsSync(screenshotsDir)) {
|
|
fs.mkdirSync(screenshotsDir, { recursive: true });
|
|
}
|
|
|
|
try {
|
|
browser = await puppeteer.launch(getPuppeteerLaunchOptions());
|
|
|
|
let page = await browser.newPage();
|
|
|
|
// Set longer timeout for CI
|
|
const timeout = isCI ? 60000 : 30000;
|
|
page.setDefaultTimeout(timeout);
|
|
page.setDefaultNavigationTimeout(timeout);
|
|
|
|
// Log console messages only if verbose
|
|
if (process.env.VERBOSE) {
|
|
page.on('console', msg => {
|
|
console.log(`[${msg.type()}] ${msg.text()}`);
|
|
});
|
|
}
|
|
|
|
// Authenticate (tries CI user first, falls back to registration)
|
|
const auth = new AuthHelper(page);
|
|
console.log('🔐 Authenticating...');
|
|
await auth.ensureAuthenticated();
|
|
page = auth.page;
|
|
|
|
console.log('\n🏠 Navigating to home page...');
|
|
await page.goto('http://127.0.0.1:5000/', { waitUntil: 'domcontentloaded' });
|
|
|
|
// Set up model configuration
|
|
console.log('🔧 Configuring model...');
|
|
const modelConfigured = await setupDefaultModel(page);
|
|
if (!modelConfigured) {
|
|
throw new Error('Failed to configure model');
|
|
}
|
|
|
|
// Wait for and fill the query field
|
|
await page.waitForSelector('#query', { timeout: 10000 });
|
|
await page.type('#query', 'What is Node.js?');
|
|
console.log('✅ Query entered');
|
|
|
|
// Check if model and search engine are pre-selected
|
|
const formValues = await page.evaluate(() => {
|
|
return {
|
|
query: document.querySelector('#query')?.value,
|
|
model: document.querySelector('#model')?.value || document.querySelector('input[name="model"]')?.value,
|
|
searchEngine: document.querySelector('#search_engine')?.value || document.querySelector('input[name="search_engine"]')?.value
|
|
};
|
|
});
|
|
console.log('📋 Form values:', formValues);
|
|
|
|
console.log('\n🚀 Submitting research...');
|
|
|
|
// Submit the form with robust retry logic
|
|
const submitButton = await page.$('button[type="submit"]');
|
|
const navigationTimeout = isCI ? 45000 : 15000;
|
|
|
|
let navigationSucceeded = false;
|
|
if (submitButton) {
|
|
try {
|
|
// Try Promise.all approach first
|
|
await Promise.all([
|
|
page.waitForNavigation({ waitUntil: 'domcontentloaded', timeout: navigationTimeout }),
|
|
submitButton.click()
|
|
]);
|
|
navigationSucceeded = true;
|
|
} catch (navError) {
|
|
console.log(` Navigation wait failed: ${navError.message}`);
|
|
// Check if we're already on a different page
|
|
const currentUrl = page.url();
|
|
if (currentUrl.includes('/research/') || currentUrl.includes('/progress/')) {
|
|
console.log(' Already navigated to research page');
|
|
navigationSucceeded = true;
|
|
} else {
|
|
// Wait a bit and check URL again
|
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
const urlAfterWait = page.url();
|
|
if (urlAfterWait.includes('/research/') || urlAfterWait.includes('/progress/')) {
|
|
console.log(' Navigation completed after wait');
|
|
navigationSucceeded = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!navigationSucceeded) {
|
|
// Try alternative submit method with Enter key
|
|
console.log(' Trying Enter key submission...');
|
|
await page.keyboard.press('Enter');
|
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
}
|
|
|
|
// Check where we ended up
|
|
const url = page.url();
|
|
console.log('📍 Current URL:', url);
|
|
|
|
if (url.includes('/research/') || url.includes('/progress/')) {
|
|
console.log('✅ Research submitted successfully!');
|
|
// URL contains /research/ - that's sufficient proof research started
|
|
// NOTE: Don't use page.evaluate() here - it hangs when the page has
|
|
// active WebSocket/SSE connections for research progress updates.
|
|
// The URL check is enough to verify successful submission.
|
|
console.log('✅ Research is processing');
|
|
console.log('\n🎉 Simple research test passed!');
|
|
process.exit(0);
|
|
} else {
|
|
// Check for error messages
|
|
const errorMessage = await page.evaluate(() => {
|
|
const alert = document.querySelector('.alert-danger, .error-message');
|
|
return alert ? alert.textContent : null;
|
|
});
|
|
|
|
if (errorMessage) {
|
|
throw new Error(`Research submission failed: ${errorMessage}`);
|
|
} else {
|
|
throw new Error(`Unexpected redirect to: ${url}`);
|
|
}
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('❌ Test failed:', error.message);
|
|
console.error('Stack trace:', error.stack);
|
|
|
|
// Take screenshot on error
|
|
if (browser) {
|
|
try {
|
|
const pages = await browser.pages();
|
|
const page = pages[0];
|
|
if (page) {
|
|
// Log current state for debugging
|
|
try {
|
|
const currentUrl = page.url();
|
|
console.log('Current URL at failure:', currentUrl);
|
|
} catch {
|
|
console.log('Could not get current URL');
|
|
}
|
|
|
|
// Skip diagnostic screenshot in CI — error context is in the logs
|
|
if (!isCI) {
|
|
try {
|
|
await page.screenshot({
|
|
path: path.join(screenshotsDir, `research_submit_error_${Date.now()}.png`),
|
|
fullPage: true
|
|
});
|
|
console.log('📸 Error screenshot saved');
|
|
} catch (screenshotError) {
|
|
console.error('Failed to save screenshot:', screenshotError.message);
|
|
}
|
|
}
|
|
}
|
|
} catch (browserError) {
|
|
console.error('Error accessing browser pages:', browserError.message);
|
|
}
|
|
}
|
|
|
|
process.exit(1);
|
|
} finally {
|
|
if (browser) {
|
|
try {
|
|
await browser.close();
|
|
} catch (closeError) {
|
|
console.error('Error closing browser:', closeError.message);
|
|
}
|
|
}
|
|
}
|
|
})();
|