Files
roa2web-service-auto/reports-app/frontend/tests/integration/console-monitoring/error-tracking.spec.js
Marius Mutu 12ac2b671e feat: Frontend CSS refactoring and test improvements
Frontend:
- Refactored CSS architecture with new utility classes
- Updated dashboard components styling
- Improved responsive grid system
- Enhanced typography and variables
- Updated E2E and integration tests

Added:
- Claude Code slash commands for validation
- SSH tunnel and start test scripts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 21:08:47 +02:00

493 lines
19 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Console Error Pattern Analysis Tests
* Analyzes frontend console errors, categorizes patterns, and monitors error frequencies
* Provides insights into application stability and potential issues
*/
import { test, expect } from '@playwright/test';
import {
authenticateWithRealCredentials,
selectCompany,
REAL_CREDENTIALS
} from '../../utils/real-auth.js';
import {
setupConsoleCapture,
ErrorClassifier,
generateErrorReport
} from '../../utils/console-monitor.js';
test.describe('Console Error Pattern Analysis', () => {
const commonErrorPatterns = [
{ pattern: /Failed to fetch/i, category: 'Network Error', severity: 'WARNING' },
{ pattern: /Network request failed/i, category: 'Network Error', severity: 'WARNING' },
{ pattern: /404.*not found/i, category: '404 Error', severity: 'WARNING' },
{ pattern: /Uncaught TypeError/i, category: 'JavaScript Error', severity: 'CRITICAL' },
{ pattern: /Uncaught ReferenceError/i, category: 'JavaScript Error', severity: 'CRITICAL' },
{ pattern: /Vue warn/i, category: 'Vue Warning', severity: 'WARNING' },
{ pattern: /Component.*not found/i, category: 'Component Error', severity: 'WARNING' },
{ pattern: /Oracle.*connection/i, category: 'Database Error', severity: 'CRITICAL' },
{ pattern: /Authentication.*failed/i, category: 'Auth Error', severity: 'CRITICAL' },
{ pattern: /Cannot read property/i, category: 'Property Error', severity: 'CRITICAL' },
{ pattern: /Cannot access before initialization/i, category: 'Initialization Error', severity: 'CRITICAL' }
];
test.beforeEach(async ({ page }) => {
setupConsoleCapture(page);
});
test.afterEach(async ({ page }) => {
const report = generateErrorReport(page, test.info().title);
if (report.summary.classifications.critical > 0) {
console.warn('🚨 Critical console errors detected:', report.details.criticalErrors);
}
// Log error pattern summary
if (Object.keys(report.details.errorPatterns).length > 0) {
console.log('📊 Error patterns detected:', report.details.errorPatterns);
}
});
test('should detect and categorize frontend errors during navigation', async ({ page }) => {
console.log('🔍 Analyzing console errors during complete navigation flow...');
// Navigate through all main application views
const navigationFlow = [
{ action: () => page.goto('/login'), name: 'Login Page' },
{ action: () => authenticateWithRealCredentials(page), name: 'Authentication' },
{ action: () => page.goto('/dashboard'), name: 'Dashboard' },
{ action: () => selectCompany(page, REAL_CREDENTIALS.company), name: 'Company Selection' },
{ action: () => page.goto('/invoices'), name: 'Invoices Page' },
{ action: () => page.goto('/payments'), name: 'Payments Page' },
{ action: () => page.goto('/dashboard'), name: 'Return to Dashboard' }
];
const errorsByStep = {};
for (const step of navigationFlow) {
console.log(`📍 Navigating to: ${step.name}`);
const initialErrorCount = (page.consoleMessages || []).length;
try {
await step.action();
await page.waitForLoadState('networkidle', { timeout: 10000 });
} catch (error) {
console.warn(`⚠️ Navigation warning for ${step.name}:`, error.message);
}
const newErrors = (page.consoleMessages || []).slice(initialErrorCount);
errorsByStep[step.name] = newErrors;
console.log(`📊 ${step.name}: ${newErrors.length} new console messages`);
}
// Analyze error patterns across all steps
const allErrors = Object.values(errorsByStep).flat();
const errorsByPattern = {};
const errorsBySeverity = { CRITICAL: 0, WARNING: 0, INFO: 0, UNKNOWN: 0 };
allErrors.forEach(error => {
// Classify by severity
const severity = ErrorClassifier.classify(error);
errorsBySeverity[severity]++;
// Classify by pattern
const pattern = commonErrorPatterns.find(p => p.pattern.test(error.text || error.error || ''));
if (pattern) {
errorsByPattern[pattern.category] = (errorsByPattern[pattern.category] || 0) + 1;
} else if (error.type === 'error') {
errorsByPattern['Unclassified Error'] = (errorsByPattern['Unclassified Error'] || 0) + 1;
}
});
console.log('📈 Error Analysis Summary:');
console.log(` Total Console Messages: ${allErrors.length}`);
console.log(` By Severity:`, errorsBySeverity);
console.log(` By Pattern:`, errorsByPattern);
// Validate error thresholds
expect(errorsBySeverity.CRITICAL, 'Critical errors detected during navigation').toBe(0);
expect(errorsBySeverity.WARNING, 'Excessive warnings during navigation').toBeLessThan(10);
// Check for high-frequency patterns
Object.entries(errorsByPattern).forEach(([pattern, count]) => {
if (count > 3) {
console.warn(`⚠️ High frequency error pattern: ${pattern} (${count} occurrences)`);
}
});
console.log('✅ Console error pattern analysis completed');
});
test('should monitor error frequencies and identify recurring issues', async ({ page }) => {
console.log('📊 Monitoring error frequencies across multiple operations...');
// Authenticate first
await authenticateWithRealCredentials(page);
await selectCompany(page, REAL_CREDENTIALS.company);
const operations = [
{ name: 'Dashboard Refresh', action: () => page.reload() },
{ name: 'Invoices Navigation', action: () => page.goto('/invoices') },
{ name: 'Payments Navigation', action: () => page.goto('/payments') },
{ name: 'Dashboard Return', action: () => page.goto('/dashboard') },
{ name: 'Company Re-selection', action: () => selectCompany(page, REAL_CREDENTIALS.company) }
];
const errorFrequencies = {};
const operationErrors = {};
for (let cycle = 0; cycle < 2; cycle++) {
console.log(`🔄 Error monitoring cycle ${cycle + 1}/2`);
for (const operation of operations) {
const initialMessageCount = (page.consoleMessages || []).length;
try {
await operation.action();
await page.waitForLoadState('networkidle', { timeout: 8000 });
} catch (error) {
console.warn(`⚠️ Operation ${operation.name} encountered issue:`, error.message);
}
const newMessages = (page.consoleMessages || []).slice(initialMessageCount);
const errorMessages = newMessages.filter(msg => msg.type === 'error' || msg.type === 'pageerror');
operationErrors[`${operation.name}_Cycle${cycle + 1}`] = errorMessages;
// Track error frequencies
errorMessages.forEach(error => {
const errorText = error.text || error.error || '';
const pattern = commonErrorPatterns.find(p => p.pattern.test(errorText));
const key = pattern ? pattern.category : 'Unclassified';
errorFrequencies[key] = (errorFrequencies[key] || 0) + 1;
});
console.log(` ${operation.name}: ${errorMessages.length} errors`);
}
}
// Analyze recurring patterns
console.log('🔍 Error Frequency Analysis:');
const recurringIssues = Object.entries(errorFrequencies)
.filter(([_pattern, count]) => count > 2)
.sort((a, b) => b[1] - a[1]);
if (recurringIssues.length > 0) {
console.log('🚨 Recurring Error Patterns:');
recurringIssues.forEach(([pattern, count]) => {
console.log(` ${pattern}: ${count} occurrences`);
});
} else {
console.log('✅ No recurring error patterns detected');
}
// Validate error thresholds
const totalErrors = Object.values(errorFrequencies).reduce((sum, count) => sum + count, 0);
expect(totalErrors, 'Excessive total errors across operations').toBeLessThan(20);
// Critical patterns should not recur
const criticalRecurring = recurringIssues.filter(([pattern]) =>
commonErrorPatterns.find(p => p.category === pattern && p.severity === 'CRITICAL')
);
expect(criticalRecurring.length, `Critical recurring errors: ${JSON.stringify(criticalRecurring)}`).toBe(0);
console.log('✅ Error frequency monitoring completed');
});
test('should detect performance-related console warnings', async ({ page }) => {
console.log('⚡ Detecting performance-related console warnings...');
await authenticateWithRealCredentials(page);
const performanceKeywords = [
'slow', 'performance', 'memory', 'leak', 'timeout',
'blocking', 'lag', 'delay', 'optimization', 'cache'
];
// Perform operations that might trigger performance warnings
const heavyOperations = [
{ name: 'Large Data Load', action: () => selectCompany(page, REAL_CREDENTIALS.company) },
{ name: 'Invoices with Filtering', action: async () => {
await page.goto('/invoices');
await page.waitForSelector('[data-testid="invoices-table"]', { timeout: 15000 });
// Trigger filtering operations
if (await page.locator('[data-testid="search-input"]').isVisible()) {
await page.fill('[data-testid="search-input"]', 'test');
await page.keyboard.press('Enter');
await page.waitForTimeout(2000);
}
}},
{ name: 'Multiple Page Navigation', action: async () => {
const pages = ['/dashboard', '/invoices', '/payments', '/dashboard'];
for (const pagePath of pages) {
await page.goto(pagePath);
await page.waitForLoadState('networkidle', { timeout: 5000 });
}
}}
];
const performanceWarnings = [];
for (const operation of heavyOperations) {
console.log(`🔧 Executing: ${operation.name}`);
const initialMessageCount = (page.consoleMessages || []).length;
const startTime = Date.now();
await operation.action();
const operationTime = Date.now() - startTime;
const newMessages = (page.consoleMessages || []).slice(initialMessageCount);
const perfMessages = newMessages.filter(msg => {
const text = msg.text || msg.error || '';
return performanceKeywords.some(keyword =>
text.toLowerCase().includes(keyword.toLowerCase())
);
});
if (perfMessages.length > 0) {
performanceWarnings.push({
operation: operation.name,
operationTime,
warnings: perfMessages,
count: perfMessages.length
});
console.log(`⚠️ ${operation.name}: ${perfMessages.length} performance warnings (${operationTime}ms)`);
} else {
console.log(`${operation.name}: No performance warnings (${operationTime}ms)`);
}
}
// Analyze performance warnings
if (performanceWarnings.length > 0) {
console.log('📊 Performance Warning Analysis:');
performanceWarnings.forEach(warning => {
console.log(` ${warning.operation}: ${warning.count} warnings, ${warning.operationTime}ms`);
warning.warnings.forEach(w => {
console.log(` - ${w.text || w.error}`);
});
});
// Performance warnings should be investigated but not fail tests
const totalPerfWarnings = performanceWarnings.reduce((sum, w) => sum + w.count, 0);
if (totalPerfWarnings > 5) {
console.warn(`⚠️ High number of performance warnings: ${totalPerfWarnings}`);
}
} else {
console.log('✅ No performance-related console warnings detected');
}
// Critical performance issues should not be present
const criticalPerfIssues = (page.consoleMessages || []).filter(msg => {
const text = msg.text || msg.error || '';
return msg.type === 'error' && performanceKeywords.some(keyword =>
text.toLowerCase().includes(keyword.toLowerCase())
);
});
expect(criticalPerfIssues.length, `Critical performance errors: ${JSON.stringify(criticalPerfIssues)}`).toBe(0);
console.log('✅ Performance warning detection completed');
});
test('should analyze error context and provide debugging information', async ({ page }) => {
console.log('🔬 Analyzing error context for debugging insights...');
await authenticateWithRealCredentials(page);
// Collect errors with context
const contextualErrors = [];
// Navigate through application collecting error context
const testScenarios = [
{
name: 'Invalid Route Access',
action: () => page.goto('/nonexistent-route'),
expectErrors: true
},
{
name: 'Rapid Navigation',
action: async () => {
await page.goto('/dashboard');
await page.goto('/invoices');
await page.goto('/payments');
await page.goto('/dashboard');
},
expectErrors: false
},
{
name: 'Form Interaction',
action: async () => {
await page.goto('/invoices');
if (await page.locator('[data-testid="search-input"]').isVisible()) {
await page.fill('[data-testid="search-input"]', 'test search');
await page.keyboard.press('Enter');
}
},
expectErrors: false
}
];
for (const scenario of testScenarios) {
console.log(`🎭 Testing scenario: ${scenario.name}`);
const initialMessageCount = (page.consoleMessages || []).length;
try {
await scenario.action();
await page.waitForLoadState('networkidle', { timeout: 8000 });
} catch (error) {
console.log(` Expected error in ${scenario.name}:`, error.message);
}
const newMessages = (page.consoleMessages || []).slice(initialMessageCount);
const errors = newMessages.filter(msg => msg.type === 'error' || msg.type === 'pageerror');
if (errors.length > 0) {
errors.forEach(error => {
contextualErrors.push({
scenario: scenario.name,
error: error,
url: page.url(),
timestamp: error.timestamp,
expected: scenario.expectErrors
});
});
console.log(`📍 ${scenario.name}: ${errors.length} errors (expected: ${scenario.expectErrors})`);
} else {
console.log(`${scenario.name}: No errors detected`);
}
}
// Analyze contextual errors
if (contextualErrors.length > 0) {
console.log('🔍 Contextual Error Analysis:');
// Group errors by type and scenario
const errorsByScenario = {};
const errorsByType = {};
contextualErrors.forEach(error => {
// Group by scenario
if (!errorsByScenario[error.scenario]) {
errorsByScenario[error.scenario] = [];
}
errorsByScenario[error.scenario].push(error);
// Group by error type
const errorText = error.error.text || error.error.error || '';
const pattern = commonErrorPatterns.find(p => p.pattern.test(errorText));
const category = pattern ? pattern.category : 'Unclassified';
errorsByType[category] = (errorsByType[category] || 0) + 1;
});
console.log('📊 Errors by Scenario:');
Object.entries(errorsByScenario).forEach(([scenario, errors]) => {
console.log(` ${scenario}: ${errors.length} errors`);
});
console.log('📊 Errors by Type:');
Object.entries(errorsByType).forEach(([type, count]) => {
console.log(` ${type}: ${count} occurrences`);
});
// Identify unexpected errors (those in scenarios that shouldn't have errors)
const unexpectedErrors = contextualErrors.filter(error => !error.expected);
if (unexpectedErrors.length > 0) {
console.warn('🚨 Unexpected errors detected:');
unexpectedErrors.forEach(error => {
console.warn(` ${error.scenario}: ${error.error.text || error.error.error}`);
});
// Unexpected critical errors should fail the test
const criticalUnexpected = unexpectedErrors.filter(error =>
ErrorClassifier.classify(error.error) === 'CRITICAL'
);
expect(criticalUnexpected.length, `Unexpected critical errors: ${JSON.stringify(criticalUnexpected.map(e => e.error.text))}`).toBe(0);
}
} else {
console.log('✅ No contextual errors to analyze');
}
console.log('✅ Error context analysis completed');
});
test('should generate comprehensive error report for debugging', async ({ page }) => {
console.log('📋 Generating comprehensive error report...');
// Perform full application workflow
await authenticateWithRealCredentials(page);
await selectCompany(page, REAL_CREDENTIALS.company);
const workflow = [
() => page.goto('/dashboard'),
() => page.goto('/invoices'),
() => page.goto('/payments'),
() => page.goto('/dashboard')
];
for (const step of workflow) {
await step();
await page.waitForLoadState('networkidle', { timeout: 8000 });
}
// Generate final error report
const finalReport = generateErrorReport(page, 'Complete Application Workflow');
console.log('📊 Final Error Report:');
console.log(' Test:', finalReport.testName);
console.log(' Timestamp:', finalReport.timestamp);
console.log(' Summary:', finalReport.summary);
if (finalReport.details.criticalErrors.length > 0) {
console.log('🚨 Critical Errors:');
finalReport.details.criticalErrors.forEach(error => {
console.log(` - ${error.text || error.error} (${error.location?.url || 'unknown'})`);
});
}
if (finalReport.details.warnings.length > 0) {
console.log('⚠️ Warnings:');
finalReport.details.warnings.slice(0, 5).forEach(warning => {
console.log(` - ${warning.text || warning.error}`);
});
if (finalReport.details.warnings.length > 5) {
console.log(` ... and ${finalReport.details.warnings.length - 5} more warnings`);
}
}
if (Object.keys(finalReport.details.errorPatterns).length > 0) {
console.log('📈 Error Patterns:');
Object.entries(finalReport.details.errorPatterns).forEach(([pattern, count]) => {
console.log(` ${pattern}: ${count} occurrences`);
});
}
// Performance metrics
if (finalReport.performance && finalReport.performance.apiCalls) {
const slowApiCalls = finalReport.performance.apiCalls.filter(call => call.timing > 2000);
if (slowApiCalls.length > 0) {
console.log('⚡ Slow API Calls:');
slowApiCalls.forEach(call => {
console.log(` ${call.url}: ${call.timing}ms`);
});
}
}
// Final validation
expect(finalReport.summary.classifications.critical, 'Critical errors in comprehensive workflow').toBe(0);
console.log('✅ Comprehensive error report generated successfully');
});
});