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
384 lines
14 KiB
JavaScript
384 lines
14 KiB
JavaScript
const puppeteer = require('puppeteer');
|
|
const AuthHelper = require('./auth_helper');
|
|
const fs = require('fs').promises;
|
|
const path = require('path');
|
|
const { getPuppeteerLaunchOptions } = require('./puppeteer_config');
|
|
|
|
const BASE_URL = 'http://127.0.0.1:5000';
|
|
const TIMEOUT = 120000; // 2 minutes for research to complete
|
|
|
|
// Color codes for output
|
|
const colors = {
|
|
info: '\x1b[36m',
|
|
success: '\x1b[32m',
|
|
warning: '\x1b[33m',
|
|
error: '\x1b[31m',
|
|
section: '\x1b[34m',
|
|
reset: '\x1b[0m'
|
|
};
|
|
|
|
function log(message, type = 'info') {
|
|
const timestamp = new Date().toLocaleTimeString();
|
|
console.log(`${colors[type]}[${timestamp}] ${message}${colors.reset}`);
|
|
}
|
|
|
|
async function configureSettingsForTest(page) {
|
|
log('Configuring settings for faster test...', 'info');
|
|
|
|
await page.goto(`${BASE_URL}/settings`, { waitUntil: 'domcontentloaded' });
|
|
|
|
// Set minimal iterations and questions
|
|
await page.evaluate(() => {
|
|
// Set iterations to 1
|
|
const iterationsInput = document.querySelector('input[name="app.research_iterations"]') ||
|
|
document.querySelector('#app\\.research_iterations');
|
|
if (iterationsInput) {
|
|
iterationsInput.value = '1';
|
|
iterationsInput.dispatchEvent(new Event('change', { bubbles: true }));
|
|
}
|
|
|
|
// Set questions per iteration to 1
|
|
const questionsInput = document.querySelector('input[name="app.questions_per_iteration"]') ||
|
|
document.querySelector('#app\\.questions_per_iteration');
|
|
if (questionsInput) {
|
|
questionsInput.value = '1';
|
|
questionsInput.dispatchEvent(new Event('change', { bubbles: true }));
|
|
}
|
|
|
|
// Set direct mode if available
|
|
const directModeCheckbox = document.querySelector('input[name="app.direct_mode"]') ||
|
|
document.querySelector('#app\\.direct_mode');
|
|
if (directModeCheckbox && !directModeCheckbox.checked) {
|
|
directModeCheckbox.click();
|
|
}
|
|
});
|
|
|
|
// Save settings
|
|
const saveButton = await page.$('button[type="submit"]');
|
|
if (saveButton) {
|
|
await saveButton.click();
|
|
await new Promise(r => setTimeout(r, 2000));
|
|
}
|
|
|
|
log('Settings configured', 'success');
|
|
}
|
|
|
|
async function startAndCompleteResearch(page, query) {
|
|
log(`Starting research: "${query}"`, 'info');
|
|
|
|
// Navigate to home page
|
|
await page.goto(`${BASE_URL}/`, { waitUntil: 'domcontentloaded' });
|
|
|
|
// Wait for research form
|
|
await page.waitForSelector('#research-form', { visible: true });
|
|
|
|
// Clear and type research query - use correct selector
|
|
const queryInput = await page.$('#query') || await page.$('#research_query') || await page.$('input[name="query"]');
|
|
if (queryInput) {
|
|
await queryInput.click({ clickCount: 3 }); // Select all
|
|
await queryInput.type(query);
|
|
} else {
|
|
throw new Error('Could not find query input field');
|
|
}
|
|
|
|
// Submit research
|
|
await Promise.all([
|
|
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
|
|
page.click('#start-research-btn, #submit-research, button[type="submit"]')
|
|
]);
|
|
|
|
// Get research ID from URL
|
|
const url = page.url();
|
|
const match = url.match(/\/research\/(\d+)/);
|
|
const researchId = match ? match[1] : null;
|
|
log(`Research started with ID: ${researchId}`, 'success');
|
|
|
|
// Wait for research to complete or make significant progress
|
|
log('Waiting for research to generate metrics...', 'info');
|
|
|
|
const startTime = Date.now();
|
|
const maxWaitTime = 60000; // 1 minute max
|
|
let metricsGenerated = false;
|
|
|
|
// In CI, don't wait long for research
|
|
while (Date.now() - startTime < 10000 && !metricsGenerated) { // Only wait 10 seconds
|
|
try {
|
|
// Check research status with error handling
|
|
const status = await page.evaluate(() => {
|
|
const statusEl = document.querySelector('.status-text, .research-status, .status');
|
|
const progressEl = document.querySelector('.progress-bar, .search-progress');
|
|
const searchCount = document.querySelector('.search-count, .searches-completed');
|
|
const tokenCount = document.querySelector('.token-count, .tokens-used');
|
|
|
|
const statusText = statusEl ? statusEl.textContent.toLowerCase() : '';
|
|
const hasProgress = Boolean(progressEl);
|
|
const hasSearches = Boolean(searchCount);
|
|
const hasTokens = Boolean(tokenCount);
|
|
|
|
return {
|
|
text: statusText,
|
|
isComplete: statusText.includes('complet') || statusText.includes('finish'),
|
|
hasProgress,
|
|
hasSearches,
|
|
hasTokens,
|
|
hasMetrics: hasSearches || hasTokens
|
|
};
|
|
});
|
|
|
|
if (status.isComplete) {
|
|
log('Research completed!', 'success');
|
|
metricsGenerated = true;
|
|
break;
|
|
}
|
|
|
|
if (status.hasMetrics) {
|
|
log('Research has generated some metrics', 'info');
|
|
metricsGenerated = true;
|
|
}
|
|
|
|
// Log progress
|
|
if (status.text) {
|
|
log(`Status: ${status.text}`, 'info');
|
|
}
|
|
|
|
} catch {
|
|
// Page might be reloading
|
|
}
|
|
|
|
await new Promise(r => setTimeout(r, 1000)); // Check more frequently
|
|
}
|
|
|
|
if (!metricsGenerated) {
|
|
log('Research is still running, but proceeding to check metrics...', 'warning');
|
|
}
|
|
|
|
return researchId;
|
|
}
|
|
|
|
async function captureMetricsDashboard(page, timestamp) {
|
|
log('Navigating to metrics dashboard...', 'info');
|
|
|
|
// Navigate to metrics page
|
|
await page.goto(`${BASE_URL}/metrics`, { waitUntil: 'domcontentloaded' });
|
|
|
|
// Wait for page to load
|
|
await page.waitForSelector('body');
|
|
await new Promise(r => setTimeout(r, 3000)); // Give time for data to load
|
|
|
|
// Capture all metrics data
|
|
const metricsData = await page.evaluate(() => {
|
|
const data = {
|
|
timestamp: new Date().toISOString(),
|
|
url: window.location.href,
|
|
pageTitle: document.title,
|
|
tokenMetrics: {},
|
|
searchMetrics: {},
|
|
researchMetrics: {},
|
|
chartData: {},
|
|
rawContent: '',
|
|
elements: {}
|
|
};
|
|
|
|
// Get page content
|
|
data.rawContent = document.body.innerText.substring(0, 2000);
|
|
|
|
// Look for token usage metrics
|
|
const tokenElements = [
|
|
{ selector: '.total-tokens', label: 'Total Tokens' },
|
|
{ selector: '.prompt-tokens', label: 'Prompt Tokens' },
|
|
{ selector: '.completion-tokens', label: 'Completion Tokens' },
|
|
{ selector: '.token-count', label: 'Token Count' },
|
|
{ selector: '.usage-value', label: 'Usage Value' },
|
|
{ selector: '[data-metric="tokens"]', label: 'Token Metric' }
|
|
];
|
|
|
|
tokenElements.forEach(({ selector, label }) => {
|
|
const el = document.querySelector(selector);
|
|
if (el) {
|
|
data.tokenMetrics[label] = el.textContent.trim();
|
|
}
|
|
});
|
|
|
|
// Look for search metrics
|
|
const searchElements = [
|
|
{ selector: '.search-count', label: 'Search Count' },
|
|
{ selector: '.searches-completed', label: 'Searches Completed' },
|
|
{ selector: '.search-calls', label: 'Search Calls' },
|
|
{ selector: '[data-metric="searches"]', label: 'Search Metric' }
|
|
];
|
|
|
|
searchElements.forEach(({ selector, label }) => {
|
|
const el = document.querySelector(selector);
|
|
if (el) {
|
|
data.searchMetrics[label] = el.textContent.trim();
|
|
}
|
|
});
|
|
|
|
// Look for metric cards or stat boxes
|
|
const metricCards = document.querySelectorAll('.metric-card, .stat-box, .metric-item, .dashboard-card');
|
|
metricCards.forEach(card => {
|
|
const title = card.querySelector('.metric-title, .card-title, h3, h4, .label');
|
|
const value = card.querySelector('.metric-value, .card-value, .value, .number, span');
|
|
if (title && value) {
|
|
const key = title.textContent.trim();
|
|
const val = value.textContent.trim();
|
|
if (key.toLowerCase().includes('token')) {
|
|
data.tokenMetrics[key] = val;
|
|
} else if (key.toLowerCase().includes('search')) {
|
|
data.searchMetrics[key] = val;
|
|
} else {
|
|
data.researchMetrics[key] = val;
|
|
}
|
|
}
|
|
});
|
|
|
|
// Look for tables with metrics
|
|
const tables = document.querySelectorAll('table');
|
|
tables.forEach((table, index) => {
|
|
const headers = Array.from(table.querySelectorAll('th')).map(th => th.textContent.trim());
|
|
const rows = Array.from(table.querySelectorAll('tbody tr')).map(tr => {
|
|
return Array.from(tr.querySelectorAll('td')).map(td => td.textContent.trim());
|
|
});
|
|
if (headers.length > 0 || rows.length > 0) {
|
|
data.chartData[`table_${index}`] = { headers, rows };
|
|
}
|
|
});
|
|
|
|
// Look for canvas elements (charts)
|
|
const canvases = document.querySelectorAll('canvas');
|
|
data.elements.canvasCount = canvases.length;
|
|
|
|
// Check for Chart.js
|
|
data.elements.hasChartJS = typeof Chart !== 'undefined';
|
|
|
|
return data;
|
|
});
|
|
|
|
// Log findings
|
|
log('\n=== METRICS DASHBOARD ANALYSIS ===', 'section');
|
|
|
|
log('\nToken Metrics Found:', 'info');
|
|
if (Object.keys(metricsData.tokenMetrics).length > 0) {
|
|
console.log(JSON.stringify(metricsData.tokenMetrics, null, 2));
|
|
} else {
|
|
log('No token metrics found', 'warning');
|
|
}
|
|
|
|
log('\nSearch Metrics Found:', 'info');
|
|
if (Object.keys(metricsData.searchMetrics).length > 0) {
|
|
console.log(JSON.stringify(metricsData.searchMetrics, null, 2));
|
|
} else {
|
|
log('No search metrics found', 'warning');
|
|
}
|
|
|
|
log('\nOther Research Metrics:', 'info');
|
|
if (Object.keys(metricsData.researchMetrics).length > 0) {
|
|
console.log(JSON.stringify(metricsData.researchMetrics, null, 2));
|
|
} else {
|
|
log('No other metrics found', 'warning');
|
|
}
|
|
|
|
log('\nPage Elements:', 'info');
|
|
console.log(`- Canvas elements: ${metricsData.elements.canvasCount}`);
|
|
console.log(`- Chart.js loaded: ${metricsData.elements.hasChartJS}`);
|
|
console.log(`- Tables found: ${Object.keys(metricsData.chartData).length}`);
|
|
|
|
// Show snippet of raw content
|
|
log('\nRaw page content preview:', 'info');
|
|
console.log(metricsData.rawContent.substring(0, 500) + '...');
|
|
|
|
|
|
// Save full data
|
|
const dataPath = path.join(__dirname, `metrics-full-data-${timestamp}.json`);
|
|
await fs.writeFile(dataPath, JSON.stringify(metricsData, null, 2));
|
|
log(`Full data saved: ${dataPath}`, 'success');
|
|
|
|
// Determine success
|
|
const hasTokenData = Object.keys(metricsData.tokenMetrics).length > 0;
|
|
const hasSearchData = Object.keys(metricsData.searchMetrics).length > 0;
|
|
const hasAnyData = hasTokenData || hasSearchData || Object.keys(metricsData.researchMetrics).length > 0;
|
|
|
|
return { hasTokenData, hasSearchData, hasAnyData, metricsData };
|
|
}
|
|
|
|
async function testMetricsFullFlow() {
|
|
const browser = await puppeteer.launch(getPuppeteerLaunchOptions());
|
|
|
|
const page = await browser.newPage();
|
|
page.setDefaultTimeout(TIMEOUT);
|
|
|
|
// Log console errors
|
|
page.on('console', msg => {
|
|
if (msg.type() === 'error') {
|
|
log(`Browser error: ${msg.text()}`, 'error');
|
|
}
|
|
});
|
|
|
|
try {
|
|
// Create test user with special characters in password
|
|
const timestamp = Date.now();
|
|
const username = `metrics_${timestamp}`;
|
|
const password = `test'pass"with$pecial`;
|
|
|
|
log('\n=== FULL METRICS FLOW TEST ===', 'section');
|
|
log(`Username: ${username}`, 'info');
|
|
log(`Password: ${password} (with special characters)`, 'info');
|
|
|
|
// Step 1: Register/Login
|
|
log('\n=== AUTHENTICATION ===', 'section');
|
|
const auth = new AuthHelper(page, BASE_URL);
|
|
await auth.register(username, password);
|
|
|
|
// Step 2: Configure settings for fast test
|
|
log('\n=== CONFIGURING SETTINGS ===', 'section');
|
|
await configureSettingsForTest(page);
|
|
|
|
// Step 3: Run a research
|
|
log('\n=== RUNNING RESEARCH ===', 'section');
|
|
const researchId = await startAndCompleteResearch(page, "What are the top 3 benefits of renewable energy?");
|
|
|
|
// Step 4: Navigate around to ensure metrics are saved
|
|
log('\n=== GENERATING ADDITIONAL ACTIVITY ===', 'section');
|
|
|
|
// Visit history
|
|
await page.goto(`${BASE_URL}/history`, { waitUntil: 'domcontentloaded' });
|
|
log('Visited history page', 'success');
|
|
await new Promise(r => setTimeout(r, 2000));
|
|
|
|
// Go back to research
|
|
if (researchId) {
|
|
await page.goto(`${BASE_URL}/research/${researchId}`, { waitUntil: 'domcontentloaded' });
|
|
log('Returned to research page', 'success');
|
|
await new Promise(r => setTimeout(r, 2000));
|
|
}
|
|
|
|
// Step 5: Check metrics dashboard
|
|
log('\n=== CHECKING METRICS DASHBOARD ===', 'section');
|
|
const { hasTokenData, hasSearchData, hasAnyData } = await captureMetricsDashboard(page, timestamp);
|
|
|
|
// Final verdict
|
|
log('\n=== TEST RESULTS ===', 'section');
|
|
if (hasTokenData && hasSearchData) {
|
|
log('✅ METRICS DASHBOARD IS FULLY WORKING!', 'success');
|
|
log('✅ Both token and search metrics are displayed', 'success');
|
|
} else if (hasAnyData) {
|
|
log('⚠️ METRICS DASHBOARD IS PARTIALLY WORKING', 'warning');
|
|
log(`Token metrics: ${hasTokenData ? '✅' : '❌'}`, hasTokenData ? 'success' : 'error');
|
|
log(`Search metrics: ${hasSearchData ? '✅' : '❌'}`, hasSearchData ? 'success' : 'error');
|
|
} else {
|
|
log('❌ METRICS DASHBOARD IS NOT SHOWING ANY DATA', 'error');
|
|
}
|
|
|
|
} catch (error) {
|
|
log(`\n❌ Test failed: ${error.message}`, 'error');
|
|
console.error(error);
|
|
|
|
} finally {
|
|
// Close browser properly
|
|
await browser.close();
|
|
}
|
|
}
|
|
|
|
// Run the test
|
|
testMetricsFullFlow().catch(console.error);
|