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
341 lines
12 KiB
JavaScript
341 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 = `details_test_${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 registerAndLogin(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 createAndWaitForResearch(page) {
|
|
log('🔬 Creating research for details test...', 'info');
|
|
|
|
await page.goto(`${BASE_URL}/research`);
|
|
await page.waitForSelector('#query');
|
|
|
|
// Set a specific query
|
|
const testQuery = 'Benefits of green tea for health';
|
|
await page.evaluate((q) => {
|
|
document.getElementById('query').value = q;
|
|
}, testQuery);
|
|
|
|
// Submit research
|
|
await page.click('#submit-research');
|
|
|
|
// Wait for research to complete
|
|
log('⏳ Waiting for research to complete...', 'info');
|
|
const startTime = Date.now();
|
|
const maxWaitTime = 120000; // 2 minutes
|
|
|
|
while (Date.now() - startTime < maxWaitTime) {
|
|
const progressText = await page.$eval('.progress-info', el => el.textContent).catch(() => '');
|
|
|
|
if (progressText.includes('100%') || progressText.includes('completed')) {
|
|
log('✅ Research completed', 'success');
|
|
break;
|
|
}
|
|
|
|
await delay(1000);
|
|
}
|
|
|
|
// Get research ID from URL or page
|
|
const researchId = await page.evaluate(() => {
|
|
// Try to extract from URL or page elements
|
|
const urlMatch = window.location.pathname.match(/research\/([a-f0-9-]+)/);
|
|
if (urlMatch) return urlMatch[1];
|
|
|
|
// Try to find in page data
|
|
const researchLink = document.querySelector('a[href*="/results/"]');
|
|
if (researchLink) {
|
|
const match = researchLink.href.match(/results\/([a-f0-9-]+)/);
|
|
if (match) return match[1];
|
|
}
|
|
|
|
return null;
|
|
});
|
|
|
|
return { query: testQuery, id: researchId };
|
|
}
|
|
|
|
async function testResearchDetails() {
|
|
const browser = await puppeteer.launch(getPuppeteerLaunchOptions());
|
|
|
|
const page = await browser.newPage();
|
|
|
|
// Set console log handler
|
|
page.on('console', msg => {
|
|
if (msg.type() === 'error') {
|
|
log(`Browser console error: ${msg.text()}`, 'error');
|
|
}
|
|
});
|
|
|
|
try {
|
|
// Register and login
|
|
await registerAndLogin(page);
|
|
|
|
// Create a research and wait for completion
|
|
const research = await createAndWaitForResearch(page);
|
|
|
|
// Navigate to details page
|
|
log('\n=== TESTING RESEARCH DETAILS PAGE ===', 'section');
|
|
|
|
// First go to history to find the research
|
|
await page.goto(`${BASE_URL}/history`);
|
|
await page.waitForSelector('.history-item');
|
|
|
|
// Click on the first research item
|
|
const detailsLink = await page.$('.history-item a[href*="/details/"], .history-item a[href*="/results/"]');
|
|
if (detailsLink) {
|
|
await detailsLink.click();
|
|
await page.waitForNavigation();
|
|
} else if (research.id) {
|
|
// Try direct navigation if we have the ID
|
|
await page.goto(`${BASE_URL}/results/${research.id}`);
|
|
}
|
|
|
|
// Wait for details page to load
|
|
await page.waitForSelector('.report-content, .results-container', { timeout: 10000 });
|
|
|
|
// Capture details page content
|
|
const pageDetails = await page.evaluate(() => {
|
|
const details = {
|
|
title: document.title,
|
|
url: window.location.href,
|
|
hasReport: !!document.querySelector('.report-content, .markdown-content'),
|
|
sections: [],
|
|
metadata: {},
|
|
actions: {
|
|
hasDownloadButton: !!document.querySelector('.download-btn, [data-action="download"]'),
|
|
hasExportButton: !!document.querySelector('.export-btn, [data-action="export"]'),
|
|
hasPrintButton: !!document.querySelector('.print-btn, [data-action="print"]'),
|
|
hasShareButton: !!document.querySelector('.share-btn, [data-action="share"]'),
|
|
hasBackButton: !!document.querySelector('.back-btn, a[href*="/history"]')
|
|
}
|
|
};
|
|
|
|
// Get report sections
|
|
const headings = document.querySelectorAll('h1, h2, h3');
|
|
headings.forEach(h => {
|
|
details.sections.push({
|
|
level: h.tagName,
|
|
text: h.textContent.trim()
|
|
});
|
|
});
|
|
|
|
// Get metadata if available
|
|
const metaElements = document.querySelectorAll('.metadata-item, .meta-info, .research-info');
|
|
metaElements.forEach(el => {
|
|
const label = el.querySelector('.label, .meta-label')?.textContent || '';
|
|
const value = el.querySelector('.value, .meta-value')?.textContent || el.textContent;
|
|
if (label) {
|
|
details.metadata[label] = value;
|
|
}
|
|
});
|
|
|
|
// Check for citations
|
|
details.hasCitations = document.querySelectorAll('a[href*="http"], .citation, .reference').length > 0;
|
|
|
|
// Check for research metrics
|
|
details.hasMetrics = !!document.querySelector('.metrics, .research-metrics, .statistics');
|
|
|
|
return details;
|
|
});
|
|
|
|
log('📊 Details page content:', 'info');
|
|
log(` - URL: ${pageDetails.url}`, 'info');
|
|
log(` - Has report content: ${pageDetails.hasReport}`, 'info');
|
|
log(` - Number of sections: ${pageDetails.sections.length}`, 'info');
|
|
log(` - Has citations: ${pageDetails.hasCitations}`, 'info');
|
|
log(` - Has metrics: ${pageDetails.hasMetrics}`, 'info');
|
|
|
|
// Verify essential elements
|
|
if (!pageDetails.hasReport) {
|
|
throw new Error('No report content found on details page');
|
|
}
|
|
log('✅ Report content present', 'success');
|
|
|
|
if (pageDetails.sections.length > 0) {
|
|
log(`✅ Found ${pageDetails.sections.length} sections in report`, 'success');
|
|
pageDetails.sections.slice(0, 5).forEach(section => {
|
|
log(` - ${section.level}: ${section.text}`, 'info');
|
|
});
|
|
}
|
|
|
|
// Test export functionality
|
|
log('\n=== TESTING EXPORT OPTIONS ===', 'section');
|
|
|
|
if (pageDetails.actions.hasExportButton) {
|
|
const exportButton = await page.$('.export-btn, [data-action="export"]');
|
|
await exportButton.click();
|
|
await delay(500);
|
|
|
|
// Check for export options
|
|
const exportOptions = await page.evaluate(() => {
|
|
const options = [];
|
|
const exportLinks = document.querySelectorAll('.export-option, .export-format, a[download]');
|
|
exportLinks.forEach(link => {
|
|
options.push({
|
|
format: link.textContent || link.getAttribute('data-format') || '',
|
|
href: link.href || ''
|
|
});
|
|
});
|
|
return options;
|
|
});
|
|
|
|
if (exportOptions.length > 0) {
|
|
log(`✅ Found ${exportOptions.length} export formats:`, 'success');
|
|
exportOptions.forEach(opt => {
|
|
log(` - ${opt.format}`, 'info');
|
|
});
|
|
}
|
|
}
|
|
|
|
// Test download functionality
|
|
if (pageDetails.actions.hasDownloadButton) {
|
|
log('✅ Download option available', 'success');
|
|
}
|
|
|
|
// Test print functionality
|
|
if (pageDetails.actions.hasPrintButton) {
|
|
log('✅ Print option available', 'success');
|
|
}
|
|
|
|
// Test navigation
|
|
log('\n=== TESTING NAVIGATION ===', 'section');
|
|
|
|
if (pageDetails.actions.hasBackButton) {
|
|
const backButton = await page.$('.back-btn, a[href*="/history"]');
|
|
await backButton.click();
|
|
await page.waitForNavigation();
|
|
|
|
const afterNavUrl = page.url();
|
|
if (afterNavUrl.includes('/history')) {
|
|
log('✅ Back navigation to history works', 'success');
|
|
|
|
// Navigate back to details
|
|
await page.goBack();
|
|
await page.waitForSelector('.report-content, .results-container');
|
|
}
|
|
}
|
|
|
|
// Test interactive elements
|
|
log('\n=== TESTING INTERACTIVE ELEMENTS ===', 'section');
|
|
|
|
// Check for collapsible sections
|
|
const collapsibles = await page.$$('.collapsible, .accordion, details');
|
|
if (collapsibles.length > 0) {
|
|
log(`📊 Found ${collapsibles.length} collapsible sections`, 'info');
|
|
|
|
// Test first collapsible
|
|
await collapsibles[0].click();
|
|
await delay(300);
|
|
log('✅ Collapsible sections work', 'success');
|
|
}
|
|
|
|
// Check for copy buttons
|
|
const copyButtons = await page.$$('.copy-btn, [data-action="copy"]');
|
|
if (copyButtons.length > 0) {
|
|
log(`📊 Found ${copyButtons.length} copy buttons`, 'info');
|
|
log('✅ Copy functionality available', 'success');
|
|
}
|
|
|
|
// Capture final screenshot
|
|
await page.screenshot({
|
|
path: path.join(__dirname, 'screenshots', 'research_details_final.png'),
|
|
fullPage: true
|
|
});
|
|
|
|
// Test metrics section if available
|
|
if (pageDetails.hasMetrics) {
|
|
log('\n=== TESTING METRICS SECTION ===', 'section');
|
|
|
|
const metrics = await page.evaluate(() => {
|
|
const metricsData = {};
|
|
const metricElements = document.querySelectorAll('.metric, .stat, [data-metric]');
|
|
|
|
metricElements.forEach(el => {
|
|
const label = el.querySelector('.metric-label, .label')?.textContent ||
|
|
el.getAttribute('data-metric') || '';
|
|
const value = el.querySelector('.metric-value, .value')?.textContent ||
|
|
el.textContent;
|
|
if (label) {
|
|
metricsData[label] = value;
|
|
}
|
|
});
|
|
|
|
return metricsData;
|
|
});
|
|
|
|
log('📊 Research metrics:', 'info');
|
|
Object.entries(metrics).forEach(([key, value]) => {
|
|
log(` - ${key}: ${value}`, 'info');
|
|
});
|
|
}
|
|
|
|
log('\n✅ Research details page test completed successfully!', 'success');
|
|
|
|
} catch (error) {
|
|
log(`\n❌ Test failed: ${error.message}`, 'error');
|
|
|
|
// Capture error screenshot
|
|
await page.screenshot({
|
|
path: path.join(__dirname, 'screenshots', 'research_details_error.png'),
|
|
fullPage: true
|
|
});
|
|
|
|
throw error;
|
|
} finally {
|
|
await browser.close();
|
|
}
|
|
}
|
|
|
|
// Run the test
|
|
testResearchDetails().catch(error => {
|
|
console.error('Test execution failed:', error);
|
|
process.exit(1);
|
|
});
|