//! ๐ŸŒ COMPREHENSIVE REAL-WORLD TESTING SUITE //! Created: 2025-08-04 //! Purpose: Test complete application flows with real data and interactions import { test, expect } from '@playwright/test'; import { LoginPage } from '../page-objects/LoginPage.js'; import { DashboardPage } from '../page-objects/DashboardPage.js'; test.describe('๐ŸŒ ROA2WEB Real-World Comprehensive Testing', () => { let loginPage; let dashboardPage; let performanceMetrics = []; let networkErrors = []; let consoleErrors = []; test.beforeEach(async ({ page }) => { // Reset metrics performanceMetrics = []; networkErrors = []; consoleErrors = []; // Setup comprehensive monitoring page.on('response', response => { const timing = { url: response.url(), status: response.status(), timing: response.request().timing(), size: response.headers()['content-length'] || 0, timestamp: new Date().toISOString() }; performanceMetrics.push(timing); if (response.status() >= 400) { networkErrors.push({ url: response.url(), status: response.status(), statusText: response.statusText() }); } }); page.on('console', msg => { if (msg.type() === 'error') { consoleErrors.push({ text: msg.text(), location: msg.location(), timestamp: new Date().toISOString() }); } }); loginPage = new LoginPage(page); dashboardPage = new DashboardPage(page); }); test('๐ŸŽฏ COMPLETE USER JOURNEY - Login to Dashboard to Reports', async ({ page }) => { console.log('\n๐ŸŒ === COMPLETE USER JOURNEY TEST ==='); const startTime = Date.now(); // Phase 1: Navigate to Login console.log('\n๐Ÿ“ Phase 1: Navigate to Login'); await loginPage.navigate(); await page.screenshot({ path: 'journey-01-login-page.png' }); // Verify login page loads correctly await expect(page).toHaveTitle(/ROA Reports/); console.log('โœ… Login page loaded'); // Phase 2: Attempt Authentication with Real Credentials console.log('\n๐Ÿ“ Phase 2: Authentication Flow'); // Test with test credentials first await page.fill('#username', 'MARIUS M'); await page.fill('#password input', 'PAROLA9911'); // Verify button becomes enabled await page.waitForTimeout(200); const buttonEnabled = !(await page.locator('button[type="submit"]').isDisabled()); expect(buttonEnabled).toBe(true); console.log('โœ… Login button enabled with credentials'); // Monitor the authentication request const authPromise = page.waitForResponse('**/auth/login').catch(() => null); await page.click('button[type="submit"]'); const authResponse = await authPromise; if (authResponse) { console.log(`๐Ÿ“Š Auth Response: ${authResponse.status()}`); if (authResponse.status() === 200) { console.log('โœ… Authentication successful'); // Wait for redirect to dashboard await page.waitForURL('**/dashboard', { timeout: 10000 }).catch(() => { console.log('โš ๏ธ No redirect to dashboard - checking current state'); }); } else if (authResponse.status() === 422) { console.log('โŒ Validation error - checking response'); const responseBody = await authResponse.text(); console.log('Response body:', responseBody); } else if (authResponse.status() === 401) { console.log('โŒ Authentication failed - invalid credentials'); } else { console.log(`โŒ Unexpected response: ${authResponse.status()}`); } } else { console.log('โš ๏ธ No authentication response received'); } await page.screenshot({ path: 'journey-02-after-auth.png' }); // Phase 3: Dashboard Interaction (if successful) const currentUrl = page.url(); console.log(`๐Ÿ“ Current URL: ${currentUrl}`); if (currentUrl.includes('/dashboard')) { console.log('\n๐Ÿ“ Phase 3: Dashboard Interaction'); // Wait for dashboard to load await page.waitForSelector('.dashboard-container', { timeout: 5000 }).catch(() => { console.log('โš ๏ธ Dashboard container not found'); }); // Test dashboard functionality const companySelector = page.locator('select, .p-dropdown'); if (await companySelector.first().isVisible()) { console.log('โœ… Company selector visible'); // Try to select a company await companySelector.first().click(); await page.waitForTimeout(500); const options = page.locator('.p-dropdown-item'); const optionCount = await options.count(); if (optionCount > 0) { await options.first().click(); console.log('โœ… Company selected'); // Wait for data to load await page.waitForTimeout(2000); // Check if statistics are displayed const statsCards = page.locator('.stat-card, .dashboard-stat, .metric-card'); const statsCount = await statsCards.count(); console.log(`๐Ÿ“Š Statistics cards found: ${statsCount}`); } } await page.screenshot({ path: 'journey-03-dashboard.png' }); // Phase 4: Navigation Test console.log('\n๐Ÿ“ Phase 4: Navigation Test'); const navLinks = page.locator('nav a, .nav-link, .menu-item'); const navCount = await navLinks.count(); console.log(`๐Ÿงญ Navigation links found: ${navCount}`); if (navCount > 0) { // Try to navigate to invoices const invoicesLink = page.locator('text=/facturi|invoice/i').first(); if (await invoicesLink.isVisible()) { await invoicesLink.click(); await page.waitForTimeout(1000); console.log('โœ… Navigated to invoices'); await page.screenshot({ path: 'journey-04-invoices.png' }); } } } const totalTime = Date.now() - startTime; console.log(`\nโฑ๏ธ Total journey time: ${totalTime}ms`); }); test('๐Ÿ” NETWORK PERFORMANCE ANALYSIS', async ({ page }) => { console.log('\n๐Ÿ” === NETWORK PERFORMANCE ANALYSIS ==='); // Navigate and monitor performance await loginPage.navigate(); // Wait for all initial requests to complete await page.waitForLoadState('networkidle'); // Analyze performance metrics const slowRequests = performanceMetrics.filter(metric => { const timing = metric.timing; return timing && (timing.responseEnd - timing.requestStart) > 2000; }); const failedRequests = performanceMetrics.filter(metric => metric.status >= 400); console.log(`๐Ÿ“Š Total requests: ${performanceMetrics.length}`); console.log(`๐ŸŒ Slow requests (>2s): ${slowRequests.length}`); console.log(`โŒ Failed requests: ${failedRequests.length}`); if (slowRequests.length > 0) { console.log('\n๐ŸŒ Slow requests:'); slowRequests.forEach(request => { const duration = request.timing ? (request.timing.responseEnd - request.timing.requestStart) : 'unknown'; console.log(` - ${request.url}: ${duration}ms`); }); } if (failedRequests.length > 0) { console.log('\nโŒ Failed requests:'); failedRequests.forEach(request => { console.log(` - ${request.status} ${request.url}`); }); } // Performance assertions expect(slowRequests.length).toBeLessThan(5); // Max 5 slow requests expect(failedRequests.length).toBeLessThan(3); // Max 3 failed requests }); test('๐Ÿงช ERROR HANDLING STRESS TEST', async ({ page }) => { console.log('\n๐Ÿงช === ERROR HANDLING STRESS TEST ==='); await loginPage.navigate(); // Test various error scenarios const errorScenarios = [ { name: 'Server Error 500', setup: () => page.route('**/auth/login', route => route.fulfill({ status: 500, body: '{"detail": "Internal server error"}' }) ) }, { name: 'Network Timeout', setup: () => page.route('**/auth/login', route => route.abort('timeout')) }, { name: 'Invalid JSON Response', setup: () => page.route('**/auth/login', route => route.fulfill({ status: 200, body: 'invalid json' }) ) }, { name: 'Rate Limiting 429', setup: () => page.route('**/auth/login', route => route.fulfill({ status: 429, body: '{"detail": "Too many requests"}' }) ) } ]; for (const scenario of errorScenarios) { console.log(`\n--- Testing: ${scenario.name} ---`); // Setup error scenario await scenario.setup(); // Fill credentials and submit await page.fill('#username', 'test'); await page.fill('#password input', 'test'); await page.click('button[type="submit"]'); // Wait for error handling await page.waitForTimeout(3000); // Check if error is handled gracefully const errorMessage = await page.locator('.error-message, .p-toast-error').isVisible(); console.log(`Error message shown: ${errorMessage}`); // Verify user is still on login page const isOnLogin = await loginPage.isOnLoginPage(); console.log(`Still on login page: ${isOnLogin}`); expect(isOnLogin).toBe(true); // Clear the route override await page.unroute('**/auth/login'); // Clear form for next test await page.fill('#username', ''); await page.fill('#password input', ''); await page.waitForTimeout(500); } }); test('๐Ÿ“ฑ RESPONSIVE DESIGN VALIDATION', async ({ page }) => { console.log('\n๐Ÿ“ฑ === RESPONSIVE DESIGN VALIDATION ==='); const viewports = [ { name: 'Mobile Portrait', width: 375, height: 667 }, { name: 'Mobile Landscape', width: 667, height: 375 }, { name: 'Tablet', width: 768, height: 1024 }, { name: 'Desktop', width: 1920, height: 1080 } ]; for (const viewport of viewports) { console.log(`\n--- Testing: ${viewport.name} (${viewport.width}x${viewport.height}) ---`); await page.setViewportSize({ width: viewport.width, height: viewport.height }); await loginPage.navigate(); // Wait for layout to adjust await page.waitForTimeout(500); // Check if login form is visible and accessible const formVisible = await page.locator('.login-form').isVisible(); const buttonVisible = await page.locator('button[type="submit"]').isVisible(); console.log(`Form visible: ${formVisible}`); console.log(`Button visible: ${buttonVisible}`); expect(formVisible).toBe(true); expect(buttonVisible).toBe(true); // Test form interaction await page.fill('#username', 'test'); await page.fill('#password input', 'test'); const buttonEnabled = !(await page.locator('button[type="submit"]').isDisabled()); expect(buttonEnabled).toBe(true); // Take screenshot for visual verification await page.screenshot({ path: `responsive-${viewport.name.toLowerCase().replace(' ', '-')}.png`, fullPage: true }); } }); test.afterEach(async ({ page }) => { // Generate comprehensive test report console.log('\n๐Ÿ“‹ === COMPREHENSIVE TEST REPORT ==='); console.log(`๐ŸŒ Total Network Requests: ${performanceMetrics.length}`); console.log(`โŒ Network Errors: ${networkErrors.length}`); console.log(`๐Ÿ”ฅ Console Errors: ${consoleErrors.length}`); if (networkErrors.length > 0) { console.log('\nโŒ Network Errors:'); networkErrors.forEach(error => { console.log(` - ${error.status} ${error.url}`); }); } if (consoleErrors.length > 0) { console.log('\n๐Ÿ”ฅ Console Errors:'); consoleErrors.forEach(error => { console.log(` - ${error.text}`); }); } // Performance summary const avgResponseTime = performanceMetrics.length > 0 ? performanceMetrics.reduce((sum, metric) => { const timing = metric.timing; return sum + (timing ? (timing.responseEnd - timing.requestStart) : 0); }, 0) / performanceMetrics.length : 0; console.log(`โšก Average Response Time: ${Math.round(avgResponseTime)}ms`); if (avgResponseTime > 1000) { console.log('โš ๏ธ Performance Warning: Average response time is high'); } }); });