import { test, expect } from './fixtures/auth'; import { STAGING_URL, PATHS, TIMEOUTS } from './config/staging-config'; import { CommonActions } from './utils/common-actions'; /** * Master Dashboard E2E Tests * * Tests the Master Dashboard functionality for master trainers and administrators * Verifies system-wide analytics, trainer performance data, and all events display */ // Login function for master trainer async function loginAsMasterTrainer(page: any) { await page.goto(PATHS.login); await page.fill('#user_login', 'master_trainer'); await page.fill('#user_pass', 'MasterTrainer#2025!'); await page.click('#wp-submit'); await page.waitForLoadState('networkidle'); // Verify successful login - master trainer should be able to access both dashboards const currentUrl = page.url(); console.log('Post-login URL:', currentUrl); return page; } // Login function for admin user async function loginAsAdmin(page: any) { await page.goto(PATHS.login); await page.fill('#user_login', 'admin_trainer'); await page.fill('#user_pass', 'Test123!'); await page.click('#wp-submit'); await page.waitForLoadState('networkidle'); return page; } test.describe('Master Dashboard Tests', () => { test('Master Trainer can access Master Dashboard', async ({ page }) => { test.setTimeout(30000); const actions = new CommonActions(page); await loginAsMasterTrainer(page); await actions.screenshot('master-trainer-logged-in'); // Navigate to Master Dashboard await actions.navigateAndWait('/master-dashboard/'); await actions.screenshot('master-dashboard-loaded'); // Verify page title and header await expect(page.locator('h1')).toContainText('Master Dashboard'); // Verify access is granted (no access denied message) const accessDenied = page.locator('.hvac-access-denied, text="Access Denied"'); await expect(accessDenied).toHaveCount(0); await actions.screenshot('master-dashboard-access-verified'); }); test('Administrator can access Master Dashboard', async ({ page }) => { test.setTimeout(30000); const actions = new CommonActions(page); await loginAsAdmin(page); await actions.screenshot('admin-logged-in'); // Navigate to Master Dashboard await actions.navigateAndWait('/master-dashboard/'); await actions.screenshot('admin-master-dashboard-loaded'); // Verify page title await expect(page.locator('h1')).toContainText('Master Dashboard'); // Verify access is granted const accessDenied = page.locator('.hvac-access-denied, text="Access Denied"'); await expect(accessDenied).toHaveCount(0); await actions.screenshot('admin-master-dashboard-verified'); }); test('Master Dashboard displays system overview statistics', async ({ page }) => { test.setTimeout(30000); const actions = new CommonActions(page); await loginAsMasterTrainer(page); await actions.navigateAndWait('/master-dashboard/'); // Verify System Overview section await expect(page.locator('h2')).toContainText('System Overview'); // Check that all 6 key statistics are displayed const expectedStats = [ 'Total Events', 'Upcoming Events', 'Completed Events', 'Active Trainers', 'Tickets Sold', 'Total Revenue' ]; for (const statLabel of expectedStats) { await expect(page.locator('.hvac-stat-card').filter({ hasText: statLabel })).toBeVisible(); } // Verify statistics have numeric values const statCards = page.locator('.hvac-stat-card'); const statCount = await statCards.count(); expect(statCount).toBeGreaterThanOrEqual(6); // Check that each stat card has a number for (let i = 0; i < statCount; i++) { const card = statCards.nth(i); const statValue = card.locator('p').first(); await expect(statValue).toBeVisible(); // Get the text and verify it's a number or currency const text = await statValue.textContent(); expect(text).toMatch(/^(\$?[\d,]+\.?\d*)$/); // Numbers with optional $ and commas } await actions.screenshot('system-overview-statistics-verified'); }); test('Master Dashboard shows real trainer data', async ({ page }) => { test.setTimeout(30000); const actions = new CommonActions(page); await loginAsMasterTrainer(page); await actions.navigateAndWait('/master-dashboard/'); // Look for trainer analytics section (should be after the stats) const trainerSection = page.locator('section').filter({ hasText: /Trainer.*Analytics/i }); if (await trainerSection.count() > 0) { await expect(trainerSection).toBeVisible(); await actions.screenshot('trainer-analytics-section'); // Check for trainer data table const trainersTable = page.locator('.trainers-table, table'); if (await trainersTable.count() > 0) { await expect(trainersTable).toBeVisible(); // Verify table headers const expectedHeaders = ['Trainer Name', 'Email', 'Total Events', 'Revenue']; for (const header of expectedHeaders) { await expect(page.locator('th, .table-header').filter({ hasText: header })).toBeVisible(); } await actions.screenshot('trainer-table-headers-verified'); } } else { console.log('Trainer analytics section not found or not visible'); await actions.screenshot('missing-trainer-analytics'); } }); test('Master Dashboard navigation works correctly', async ({ page }) => { test.setTimeout(30000); const actions = new CommonActions(page); await loginAsMasterTrainer(page); await actions.navigateAndWait('/master-dashboard/'); // Verify navigation buttons in header const navButtons = [ 'Your Dashboard', // Link back to regular dashboard 'Logout' ]; for (const buttonText of navButtons) { const button = page.locator('.hvac-dashboard-nav a, .ast-button').filter({ hasText: buttonText }); await expect(button.first()).toBeVisible(); } // Test navigation to regular dashboard await page.click('text="Your Dashboard"'); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(/hvac-dashboard/); await expect(page.locator('h1')).toContainText('Trainer Dashboard'); await actions.screenshot('navigated-to-regular-dashboard'); // Navigate back to master dashboard await actions.navigateAndWait('/master-dashboard/'); await expect(page.locator('h1')).toContainText('Master Dashboard'); await actions.screenshot('navigation-test-complete'); }); test('Regular trainer cannot access Master Dashboard', async ({ page }) => { test.setTimeout(30000); const actions = new CommonActions(page); // Login as regular trainer await page.goto(PATHS.login); await page.fill('#user_login', 'test_trainer'); await page.fill('#user_pass', 'Test123!'); await page.click('#wp-submit'); await page.waitForLoadState('networkidle'); await actions.screenshot('regular-trainer-logged-in'); // Try to access Master Dashboard await actions.navigateAndWait('/master-dashboard/'); // Should be redirected to regular dashboard with error await expect(page).toHaveURL(/hvac-dashboard/); // Check for error message in URL parameter const url = page.url(); expect(url).toContain('error=access_denied'); await actions.screenshot('regular-trainer-access-denied'); }); test('Master Dashboard shows accurate data with real events', async ({ page }) => { test.setTimeout(45000); const actions = new CommonActions(page); await loginAsMasterTrainer(page); await actions.navigateAndWait('/master-dashboard/'); // Get the total events count from the dashboard const totalEventsCard = page.locator('.hvac-stat-card').filter({ hasText: 'Total Events' }); await expect(totalEventsCard).toBeVisible(); const totalEventsValue = await totalEventsCard.locator('p').first().textContent(); const totalEventsNumber = parseInt(totalEventsValue || '0'); console.log(`Master Dashboard shows ${totalEventsNumber} total events`); // Verify it's a reasonable number (should be at least the test events we created) expect(totalEventsNumber).toBeGreaterThanOrEqual(0); // Get trainer count const trainersCard = page.locator('.hvac-stat-card').filter({ hasText: 'Active Trainers' }); await expect(trainersCard).toBeVisible(); const trainersValue = await trainersCard.locator('p').first().textContent(); const trainersNumber = parseInt(trainersValue || '0'); console.log(`Master Dashboard shows ${trainersNumber} active trainers`); // Should show at least our test trainers expect(trainersNumber).toBeGreaterThanOrEqual(2); // test_trainer + admin_trainer + master_trainer // Get revenue data const revenueCard = page.locator('.hvac-stat-card').filter({ hasText: 'Total Revenue' }); await expect(revenueCard).toBeVisible(); const revenueValue = await revenueCard.locator('p').first().textContent(); console.log(`Master Dashboard shows revenue: ${revenueValue}`); // Revenue should be formatted as currency expect(revenueValue).toMatch(/^\$[\d,]+\.?\d*$/); await actions.screenshot('real-data-verification-complete'); }); test('Master Dashboard performance and load time', async ({ page }) => { test.setTimeout(30000); const actions = new CommonActions(page); await loginAsMasterTrainer(page); // Measure page load time const startTime = Date.now(); await actions.navigateAndWait('/master-dashboard/'); const loadTime = Date.now() - startTime; console.log(`Master Dashboard loaded in ${loadTime}ms`); // Page should load within reasonable time (10 seconds) expect(loadTime).toBeLessThan(10000); // Verify all major sections are loaded await expect(page.locator('h1')).toContainText('Master Dashboard'); await expect(page.locator('.hvac-dashboard-stats')).toBeVisible(); // Check for any JavaScript errors const jsErrors: string[] = []; page.on('console', (msg) => { if (msg.type() === 'error') { jsErrors.push(msg.text()); } }); // Wait a bit for any delayed JS to execute await page.waitForTimeout(2000); // Log any JS errors but don't fail the test for minor issues if (jsErrors.length > 0) { console.log('JavaScript errors detected:', jsErrors); } await actions.screenshot('performance-test-complete'); }); test('Master Dashboard responsive design on mobile', async ({ browser }) => { test.setTimeout(30000); // Create mobile context const context = await browser.newContext({ viewport: { width: 375, height: 667 } // iPhone SE size }); const page = await context.newPage(); const actions = new CommonActions(page); await loginAsMasterTrainer(page); await actions.navigateAndWait('/master-dashboard/'); // Verify page loads on mobile await expect(page.locator('h1')).toContainText('Master Dashboard'); // Check that stats are displayed (they should stack on mobile) const statsSection = page.locator('.hvac-dashboard-stats'); await expect(statsSection).toBeVisible(); // Check navigation is accessible const navSection = page.locator('.hvac-dashboard-nav'); await expect(navSection).toBeVisible(); await actions.screenshot('mobile-master-dashboard'); await context.close(); }); }); test.describe('Master Dashboard Error Handling', () => { test('Handles missing data gracefully', async ({ page }) => { test.setTimeout(30000); const actions = new CommonActions(page); await loginAsMasterTrainer(page); await actions.navigateAndWait('/master-dashboard/'); // Even with no data, page should not crash await expect(page.locator('h1')).toContainText('Master Dashboard'); // Stats should show zeros or N/A, not errors const statCards = page.locator('.hvac-stat-card p'); const statCount = await statCards.count(); for (let i = 0; i < statCount; i++) { const text = await statCards.nth(i).textContent(); // Should be a number, currency, or 0, not an error message expect(text).toMatch(/^(\$?[\d,]+\.?\d*|0|N\/A)$/); } await actions.screenshot('missing-data-handled'); }); test('No PHP errors on Master Dashboard', async ({ page }) => { test.setTimeout(30000); const actions = new CommonActions(page); // Monitor for PHP errors const phpErrors: string[] = []; page.on('console', (msg) => { if (msg.type() === 'error' && msg.text().toLowerCase().includes('php')) { phpErrors.push(msg.text()); } }); await loginAsMasterTrainer(page); await actions.navigateAndWait('/master-dashboard/'); // Wait for page to fully load await page.waitForTimeout(3000); // Check that no PHP errors occurred expect(phpErrors.length).toBe(0); if (phpErrors.length > 0) { console.log('PHP errors detected:', phpErrors); await actions.screenshot('php-errors-detected'); } else { await actions.screenshot('no-php-errors'); } }); });