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

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);
}
}
}
})();