Files
roa2web-service-auto/reports-app/frontend/tests/utils/console-monitor.js
Marius Mutu 6b13ffa183 Initial commit: ROA2WEB - FastAPI + Vue.js + Telegram Bot
Modern ERP Reports Application with microservices architecture

Tech Stack:
- Backend: FastAPI + python-oracledb (Oracle DB integration)
- Frontend: Vue.js 3 + PrimeVue + Vite
- Telegram Bot: python-telegram-bot + SQLite
- Infrastructure: Shared database pool, JWT authentication, SSH tunnel

Features:
- FastAPI backend with async Oracle connection pool
- Vue.js 3 responsive frontend with PrimeVue components
- Telegram bot alternative interface
- Microservices architecture with shared components
- Complete deployment support (Linux Docker + Windows IIS)
- Comprehensive testing (Playwright E2E + pytest)

Repository Structure:
- reports-app/ - Main application (backend, frontend, telegram-bot)
- shared/ - Shared components (database pool, auth, utils)
- deployment/ - Deployment scripts (Linux & Windows)
- docs/ - Project documentation
- security/ - Security scanning and git hooks
2025-10-25 14:55:08 +03:00

317 lines
9.6 KiB
JavaScript

/**
* Console Error Monitoring Infrastructure for ROA2WEB Testing
*
* Provides comprehensive console error tracking, classification, and performance monitoring
* for Playwright tests with real Oracle data integration.
*/
/**
* Error classification system for console messages
*/
export const ErrorClassifier = {
CRITICAL: [
'Authentication failed',
'Database connection',
'Uncaught TypeError',
'Uncaught ReferenceError',
'Oracle connection error',
'SSH tunnel failed',
'Failed to authenticate',
'Cannot read property',
'Cannot access before initialization'
],
WARNING: [
'404 Not Found',
'Failed to fetch',
'Network request failed',
'Component warning',
'Vue warn',
'Resource loading error',
'Timeout exceeded',
'Connection refused'
],
INFO: [
'Development build',
'Vue devtools',
'[HMR]',
'Hot reload',
'DevTools',
'webpack',
'vite'
],
/**
* Classify a console message based on its content
* @param {Object} message - Console message object
* @returns {string} Classification level
*/
classify(message) {
const text = message.text || message.error || '';
if (this.CRITICAL.some(pattern => text.includes(pattern))) return 'CRITICAL';
if (this.WARNING.some(pattern => text.includes(pattern))) return 'WARNING';
if (this.INFO.some(pattern => text.includes(pattern))) return 'INFO';
return 'UNKNOWN';
},
/**
* Check if message should be ignored in tests
* @param {Object} message - Console message object
* @returns {boolean} True if message should be ignored
*/
shouldIgnore(message) {
const ignoredPatterns = [
'DevTools listening',
'Debugging information',
'Chrome extension',
'webpack-dev-server',
'Live reload enabled'
];
const text = message.text || message.error || '';
return ignoredPatterns.some(pattern => text.includes(pattern));
}
};
/**
* Performance monitoring utilities
*/
export const PerformanceMonitor = {
/**
* Measure page load performance metrics
* @param {Page} page - Playwright page object
* @returns {Object} Performance metrics
*/
async measurePageLoad(page) {
return await page.evaluate(() => {
const timing = performance.timing;
const navigation = performance.getEntriesByType('navigation')[0];
return {
domContentLoaded: timing.domContentLoadedEventEnd - timing.navigationStart,
loadComplete: timing.loadEventEnd - timing.navigationStart,
firstPaint: performance.getEntriesByType('paint').find(p => p.name === 'first-paint')?.startTime || 0,
firstContentfulPaint: performance.getEntriesByType('paint').find(p => p.name === 'first-contentful-paint')?.startTime || 0,
timeToInteractive: navigation?.domInteractive - navigation?.fetchStart || 0
};
});
},
/**
* Measure API response time
* @param {Page} page - Playwright page object
* @param {string} apiPattern - API endpoint pattern to monitor
* @returns {Promise<number>} Response time in milliseconds
*/
async measureApiResponse(page, apiPattern) {
const startTime = Date.now();
await page.waitForResponse(response => response.url().includes(apiPattern), { timeout: 10000 });
return Date.now() - startTime;
},
/**
* Monitor network performance during test execution
* @param {Page} page - Playwright page object
* @returns {Object} Network performance data
*/
async getNetworkMetrics(page) {
const resourceTiming = await page.evaluate(() => {
return performance.getEntriesByType('resource').map(entry => ({
name: entry.name,
duration: entry.duration,
transferSize: entry.transferSize,
type: entry.initiatorType
}));
});
const slowResources = resourceTiming
.filter(resource => resource.duration > 1000)
.sort((a, b) => b.duration - a.duration);
return {
totalResources: resourceTiming.length,
slowResources: slowResources.slice(0, 5),
averageResponseTime: resourceTiming.reduce((sum, r) => sum + r.duration, 0) / resourceTiming.length
};
}
};
/**
* Console monitoring setup function for test beforeEach hooks
* @param {Page} page - Playwright page object
* @returns {Object} Monitoring data collectors
*/
export function setupConsoleCapture(page) {
const consoleMessages = [];
const networkErrors = [];
const performanceMetrics = {
startTime: Date.now(),
apiCalls: []
};
// Capture console messages
page.on('console', msg => {
const message = {
type: msg.type(),
text: msg.text(),
location: msg.location(),
timestamp: new Date().toISOString(),
args: msg.args()
};
if (!ErrorClassifier.shouldIgnore(message)) {
consoleMessages.push(message);
}
});
// Capture JavaScript errors
page.on('pageerror', error => {
const errorMessage = {
type: 'pageerror',
error: error.message,
stack: error.stack,
timestamp: new Date().toISOString()
};
consoleMessages.push(errorMessage);
});
// Capture network failures
page.on('requestfailed', request => {
const networkError = {
url: request.url(),
method: request.method(),
failure: request.failure(),
timestamp: new Date().toISOString()
};
networkErrors.push(networkError);
});
// Monitor API responses
page.on('response', response => {
if (response.url().includes('/api/')) {
performanceMetrics.apiCalls.push({
url: response.url(),
status: response.status(),
timing: Date.now() - performanceMetrics.startTime
});
}
});
// Store collectors on page object for test access
page.consoleMessages = consoleMessages;
page.networkErrors = networkErrors;
page.performanceMetrics = performanceMetrics;
return { consoleMessages, networkErrors, performanceMetrics };
}
/**
* Generate comprehensive error report
* @param {Page} page - Playwright page object
* @param {string} testName - Name of the test
* @returns {Object} Error report
*/
export function generateErrorReport(page, testName) {
const consoleMessages = page.consoleMessages || [];
const networkErrors = page.networkErrors || [];
// Classify console messages
const classified = {
critical: consoleMessages.filter(msg => ErrorClassifier.classify(msg) === 'CRITICAL'),
warning: consoleMessages.filter(msg => ErrorClassifier.classify(msg) === 'WARNING'),
info: consoleMessages.filter(msg => ErrorClassifier.classify(msg) === 'INFO'),
unknown: consoleMessages.filter(msg => ErrorClassifier.classify(msg) === 'UNKNOWN')
};
// Find error patterns
const errorPatterns = {};
consoleMessages.forEach(msg => {
if (msg.type === 'error') {
const pattern = findErrorPattern(msg.text);
errorPatterns[pattern] = (errorPatterns[pattern] || 0) + 1;
}
});
return {
testName,
timestamp: new Date().toISOString(),
summary: {
totalConsoleMessages: consoleMessages.length,
totalNetworkErrors: networkErrors.length,
classifications: {
critical: classified.critical.length,
warning: classified.warning.length,
info: classified.info.length,
unknown: classified.unknown.length
}
},
details: {
criticalErrors: classified.critical,
warnings: classified.warning,
networkErrors,
errorPatterns
},
performance: page.performanceMetrics
};
}
/**
* Find common error patterns in console messages
* @param {string} errorText - Error message text
* @returns {string} Error pattern category
*/
function findErrorPattern(errorText) {
const patterns = [
{ pattern: /Failed to fetch/, category: 'Network Error' },
{ pattern: /404.*not found/i, category: '404 Error' },
{ pattern: /Uncaught TypeError/, category: 'JavaScript TypeError' },
{ pattern: /Vue warn/, category: 'Vue Warning' },
{ pattern: /Component.*not found/, category: 'Component Error' },
{ pattern: /Oracle.*connection/, category: 'Database Error' },
{ pattern: /Authentication.*failed/, category: 'Auth Error' }
];
const match = patterns.find(p => p.pattern.test(errorText));
return match ? match.category : 'Unknown Error';
}
/**
* Assert no critical console errors in test
* @param {Page} page - Playwright page object
* @param {Object} expect - Playwright expect object
*/
export function assertNoCriticalErrors(page, expect) {
const consoleMessages = page.consoleMessages || [];
const criticalErrors = consoleMessages.filter(msg =>
ErrorClassifier.classify(msg) === 'CRITICAL'
);
if (criticalErrors.length > 0) {
const errorDetails = criticalErrors.map(err =>
`${err.type}: ${err.text || err.error} at ${err.location?.url || 'unknown'}:${err.location?.lineNumber || 0}`
).join('\n');
expect(criticalErrors, `Critical console errors found:\n${errorDetails}`).toHaveLength(0);
}
}
/**
* Performance baselines for ROA2WEB application
*/
export const PerformanceBaselines = {
loginTime: 2000, // Max 2s for login
dashboardLoad: 3000, // Max 3s for dashboard
reportGeneration: 5000, // Max 5s for reports
apiResponse: 1500, // Max 1.5s for API calls
pageLoad: 4000 // Max 4s for page loads
};
/**
* Assert performance meets baselines
* @param {number} actualTime - Actual measured time
* @param {number} baseline - Performance baseline
* @param {string} operation - Operation name
* @param {Object} expect - Playwright expect object
*/
export function assertPerformanceBaseline(actualTime, baseline, operation, expect) {
expect(actualTime, `${operation} took ${actualTime}ms, expected < ${baseline}ms`).toBeLessThan(baseline);
}