/** * Research API Test * Direct test of the research API endpoint */ const puppeteer = require('puppeteer'); const AuthHelper = require('./auth_helper'); const { getPuppeteerLaunchOptions } = require('./puppeteer_config'); // 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 function testResearchAPI() { const browser = await puppeteer.launch(getPuppeteerLaunchOptions()); const page = await browser.newPage(); const baseUrl = 'http://127.0.0.1:5000'; const authHelper = new AuthHelper(page, baseUrl); console.log('๐Ÿ”ฌ Research API Test\n'); try { // Login first to get session cookies console.log('๐Ÿ” Getting authentication...'); await authHelper.ensureAuthenticatedWithTimeout(); // Get cookies const cookies = await page.cookies(); console.log(`โœ… Got ${cookies.length} cookies\n`); // Go to home page to get CSRF token await page.goto(baseUrl, { waitUntil: 'domcontentloaded', timeout: 30000 }); // Extract CSRF token and form defaults const pageData = await page.evaluate(() => { // Try to find CSRF token let csrfToken = ''; const csrfInput = document.querySelector('input[name="csrf_token"]'); if (csrfInput) { csrfToken = csrfInput.value; } else { // Check meta tags const csrfMeta = document.querySelector('meta[name="csrf-token"]'); if (csrfMeta) { csrfToken = csrfMeta.content; } } // Get default values return { csrf_token: csrfToken, model_provider: document.querySelector('#model_provider')?.value || 'OLLAMA', model: document.querySelector('#model, input[name="model"]')?.value || 'llama3.2:3b', search_engine: document.querySelector('#search_engine, input[name="search_engine"]')?.value || 'searxng', iterations: document.querySelector('#iterations')?.value || '2', questions_per_iteration: document.querySelector('#questions_per_iteration')?.value || '3' }; }); console.log('๐Ÿ“‹ Page data extracted:'); console.log(` CSRF Token: ${pageData.csrf_token ? 'โœ… Found' : 'โŒ Not found'}`); console.log(` Model Provider: ${pageData.model_provider}`); console.log(` Model: ${pageData.model}`); console.log(` Search Engine: ${pageData.search_engine}`); // Test 1: Try the API directly with fetch console.log('\n๐Ÿงช Test 1: Direct API call with page.evaluate()'); const apiResult1 = await page.evaluate(async () => { try { const response = await fetch('/api/start_research', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ query: 'What is 2+2?', mode: 'quick', model_provider: 'OLLAMA', model: 'llama3.2:3b', custom_endpoint: '', search_engine: 'searxng', iterations: 2, questions_per_iteration: 3, strategy: 'source-based' }) }); const text = await response.text(); return { status: response.status, statusText: response.statusText, headers: Object.fromEntries(response.headers.entries()), body: text.substring(0, 500) }; } catch (error) { return { error: error.message }; } }); console.log('API Response:'); console.log(` Status: ${apiResult1.status} ${apiResult1.statusText}`); console.log(` Body preview: ${apiResult1.body}`); // Test 2: Try with form submission simulation console.log('\n๐Ÿงช Test 2: Form submission simulation'); // Fill the form await page.type('#query', 'Test query for research'); // Intercept the next request await page.setRequestInterception(true); let capturedRequest = null; page.on('request', request => { if (request.url().includes('/api/start_research')) { capturedRequest = { url: request.url(), method: request.method(), headers: request.headers(), postData: request.postData() }; } request.continue(); }); // Click submit const submitButton = await page.$('button[type="submit"]'); if (submitButton) { await submitButton.click(); await new Promise(resolve => setTimeout(resolve, 2000)); if (capturedRequest) { console.log('Captured request:'); console.log(` Method: ${capturedRequest.method}`); console.log(` URL: ${capturedRequest.url}`); console.log(` Body: ${capturedRequest.postData}`); } } // Test 3: Check server health console.log('\n๐Ÿงช Test 3: Server health check'); const healthCheck = await page.evaluate(async () => { const endpoints = [ '/api/health', '/health', '/', '/settings/api/available-models' ]; const results = {}; for (const endpoint of endpoints) { try { const response = await fetch(endpoint); results[endpoint] = { status: response.status, ok: response.ok }; } catch (e) { results[endpoint] = { error: e.message }; } } return results; }); console.log('Health check results:'); Object.entries(healthCheck).forEach(([endpoint, result]) => { console.log(` ${endpoint}: ${result.ok ? 'โœ…' : 'โŒ'} ${result.status || result.error}`); }); // Summary console.log('\n๐Ÿ“Š Summary:'); console.log('The research API is failing with a 500 error due to SQLAlchemy transaction issues.'); console.log('This is a server-side database transaction management problem.'); console.log('\nPossible causes:'); console.log('1. Database session is being closed prematurely'); console.log('2. Multiple threads/processes accessing the same session'); console.log('3. Missing session.commit() or session.rollback() calls'); console.log('4. Flask-SQLAlchemy configuration issues'); } catch (error) { console.error('\nโŒ Test error:', error.message); } await browser.close(); console.log('\n๐Ÿ Test completed'); process.exit(0); } // Run the test testResearchAPI().catch(error => { console.error('Fatal error:', error); process.exit(1); });