/** * Trainer Management Comprehensive E2E Test Suite * * Tests all trainer management functionality including: * - Dashboard widgets and statistics * - Profile management and editing * - Venue management (CRUD operations if available) * - Organizer management system (if available) * - Training leads functionality (if available) * - Navigation consistency across all trainer pages * - Permission validation and access control * - Account status handling * * @package HVAC_Community_Events * @version 2.0.0 * @created 2025-08-27 * @assignment Agent A: Trainer Management (15 pages) */ const { test, expect } = require('@playwright/test'); const BaseTest = require('../../framework/core/BaseTest'); const TrainerDashboard = require('../../framework/page-objects/TrainerDashboard'); class TrainerManagementTestSuite extends BaseTest { constructor() { super(); this.testStartTime = Date.now(); this.evidenceCollection = []; this.emptyPageDocumentation = []; this.navigationMatrix = []; this.testResults = { pagesAccessible: 0, pagesFunctional: 0, pagesEmpty: 0, errorsDetected: 0 }; // Complete URL matrix for all trainer pages to test this.trainerPages = [ { url: '/trainer/dashboard/', name: 'Dashboard', priority: 'HIGH', expectedContent: 'Dashboard', functional: true }, { url: '/trainer/venue/list/', name: 'Venue List', priority: 'MEDIUM', expectedContent: 'Venues', functional: true }, { url: '/trainer/venue/manage/', name: 'Venue Management', priority: 'HIGH', expectedContent: 'Manage Venues', functional: false }, { url: '/trainer/organizer/manage/', name: 'Organizer Management', priority: 'HIGH', expectedContent: 'Manage Organizers', functional: false }, { url: '/trainer/profile/training-leads/', name: 'Training Leads', priority: 'HIGH', expectedContent: 'Training Leads', functional: false }, { url: '/trainer/profile/edit/', name: 'Profile Edit', priority: 'HIGH', expectedContent: 'Edit Profile', functional: true }, { url: '/trainer/profile/view/', name: 'Profile View', priority: 'MEDIUM', expectedContent: 'Profile', functional: true }, { url: '/trainer/announcements/', name: 'Announcements', priority: 'MEDIUM', expectedContent: 'Announcements', functional: true }, { url: '/trainer/resources/', name: 'Resources', priority: 'LOW', expectedContent: 'Resources', functional: true }, { url: '/trainer/documentation/', name: 'Documentation', priority: 'LOW', expectedContent: 'Documentation', functional: true }, { url: '/trainer-account-pending/', name: 'Account Pending', priority: 'MEDIUM', expectedContent: 'Account Pending', functional: true }, { url: '/trainer-account-disabled/', name: 'Account Disabled', priority: 'MEDIUM', expectedContent: 'Account Disabled', functional: true }, { url: '/trainer/events/', name: 'Event Management', priority: 'HIGH', expectedContent: 'Events', functional: true }, { url: '/trainer/create-event/', name: 'Create Event', priority: 'HIGH', expectedContent: 'Create Event', functional: true }, { url: '/trainer/training-leads/', name: 'Training Leads Management', priority: 'MEDIUM', expectedContent: 'Training Leads', functional: true } ]; } /** * Enhanced WordPress error detection using MCP browser tools */ async detectWordPressErrors() { const errors = []; try { // Use MCP browser evaluate to check for WordPress errors const errorResults = await this.page.evaluate(() => { const detectedErrors = []; // Check for PHP errors if (document.body.innerHTML.includes('Fatal error:') || document.body.innerHTML.includes('Warning:') || document.body.innerHTML.includes('Notice:')) { detectedErrors.push('PHP_ERROR'); } // Check for WordPress errors if (document.querySelector('.wp-die-message')) { detectedErrors.push('WP_DIE'); } // Check for plugin conflicts if (document.querySelector('.error-message, .notice-error')) { detectedErrors.push('PLUGIN_ERROR'); } // Check for authentication errors if (document.body.innerHTML.includes('You do not have permission') || document.body.innerHTML.includes('Access denied')) { detectedErrors.push('ACCESS_DENIED'); } // Check for empty/broken pages if (document.body.innerHTML.trim().length < 100) { detectedErrors.push('EMPTY_PAGE'); } return detectedErrors; }); errors.push(...errorResults); } catch (error) { console.warn('Error detection failed:', error.message); } return errors; } /** * Take screenshot with MCP browser tools */ async captureEvidence(name, context = '') { try { const timestamp = Date.now(); const filename = `trainer-management-${name}-${timestamp}.png`; // Take screenshot using page.screenshot (MCP compatible) await this.page.screenshot({ path: `./test-results/screenshots/${filename}`, fullPage: true }); // Get page snapshot for additional context const currentUrl = this.page.url(); const pageTitle = await this.page.title(); const evidence = { filename, context, url: currentUrl, title: pageTitle, timestamp: new Date().toISOString() }; this.evidenceCollection.push(evidence); console.log(`šŸ“ø Evidence captured: ${filename} (${context})`); return evidence; } catch (error) { console.warn('Screenshot capture failed:', error.message); return null; } } /** * Navigate to page and validate with MCP browser tools */ async navigateAndValidate(pageInfo) { try { const baseUrl = 'https://upskill-staging.measurequick.com'; const fullUrl = `${baseUrl}${pageInfo.url}`; console.log(`šŸ”— Testing page: ${pageInfo.name} (${fullUrl})`); // Navigate using standard page.goto (MCP compatible) await this.page.goto(fullUrl, { waitUntil: 'networkidle' }); // Wait for WordPress to load await this.page.waitForLoadState('domcontentloaded'); // Detect WordPress errors const errors = await this.detectWordPressErrors(); // Take evidence screenshot const evidence = await this.captureEvidence( pageInfo.name.toLowerCase().replace(/\s+/g, '-'), `Page accessibility test for ${pageInfo.name}` ); // Validate page accessibility const pageTitle = await this.page.title(); const bodyText = await this.page.textContent('body'); const hasContent = bodyText && bodyText.trim().length > 100; // Check for WordPress authentication const isAuthenticated = await this.page.evaluate(() => { return document.body.classList.contains('logged-in') || document.querySelector('#wpadminbar') !== null; }); const result = { page: pageInfo, url: fullUrl, title: pageTitle, hasContent, isAuthenticated, errors, evidence, functional: hasContent && errors.length === 0, isEmpty: !hasContent || errors.includes('EMPTY_PAGE'), timestamp: new Date().toISOString() }; // Update test results this.testResults.pagesAccessible++; if (result.functional) { this.testResults.pagesFunctional++; } if (result.isEmpty) { this.testResults.pagesEmpty++; this.emptyPageDocumentation.push(result); } if (errors.length > 0) { this.testResults.errorsDetected += errors.length; } // Add to navigation matrix this.navigationMatrix.push(result); console.log(`${result.functional ? 'āœ…' : 'āŒ'} ${pageInfo.name}: ${result.functional ? 'Functional' : 'Issues detected'}`); return result; } catch (error) { console.error(`āŒ Navigation failed for ${pageInfo.name}:`, error.message); const evidence = await this.captureEvidence( `${pageInfo.name.toLowerCase().replace(/\s+/g, '-')}-error`, `Navigation error for ${pageInfo.name}` ); const errorResult = { page: pageInfo, error: error.message, evidence, functional: false, isEmpty: true, timestamp: new Date().toISOString() }; this.testResults.errorsDetected++; this.emptyPageDocumentation.push(errorResult); this.navigationMatrix.push(errorResult); return errorResult; } } /** * Test dashboard functionality comprehensively */ async testDashboardFunctionality() { const dashboardPage = new TrainerDashboard(this.page); try { console.log('šŸŽÆ Testing Dashboard Comprehensive Functionality'); // Navigate to dashboard await dashboardPage.navigate(); await this.captureEvidence('dashboard-loaded', 'Dashboard initial load'); // Verify dashboard components await dashboardPage.verifyDashboard(); // Get dashboard statistics const stats = await dashboardPage.getDashboardStats(); console.log('šŸ“Š Dashboard Statistics:', stats); // Test dashboard widgets const widgets = ['eventCount', 'upcomingEvents', 'recentActivity']; for (const widget of widgets) { try { await dashboardPage.waitForWidget(widget); console.log(`āœ… Widget loaded: ${widget}`); } catch (error) { console.log(`āš ļø Widget not available: ${widget}`); } } // Test quick actions const quickActions = ['view-profile', 'view-venues', 'view-organizers']; for (const action of quickActions) { try { // Just verify the action exists, don't navigate (to avoid disrupting test flow) console.log(`šŸ” Checking quick action: ${action}`); await this.page.waitForSelector(`[data-action="${action}"], a[href*="${action.replace('view-', '')}"]`, { timeout: 2000 }); console.log(`āœ… Quick action available: ${action}`); } catch (error) { console.log(`āš ļø Quick action not found: ${action}`); } } // Test mobile responsiveness const responsiveness = await dashboardPage.checkMobileResponsiveness(); console.log('šŸ“± Mobile responsiveness:', responsiveness.isMobileResponsive ? 'Yes' : 'No'); // Take final dashboard screenshot await this.captureEvidence('dashboard-complete', 'Dashboard functionality testing complete'); return { success: true, stats, responsiveness, widgets: widgets.length, quickActions: quickActions.length }; } catch (error) { console.error('āŒ Dashboard testing failed:', error.message); await this.captureEvidence('dashboard-error', `Dashboard testing error: ${error.message}`); return { success: false, error: error.message }; } } /** * Test venue management functionality (if available) */ async testVenueManagement() { try { console.log('šŸ¢ Testing Venue Management Functionality'); // Test venue list page const venueListResult = await this.navigateAndValidate({ url: '/trainer/venue/list/', name: 'Venue List', priority: 'MEDIUM' }); // Test venue management page (likely empty) const venueManageResult = await this.navigateAndValidate({ url: '/trainer/venue/manage/', name: 'Venue Management', priority: 'HIGH' }); // If venue management page is functional, test CRUD operations if (venueManageResult.functional) { console.log('āœ… Venue Management page is functional - testing CRUD operations'); // Test venue form functionality const hasCreateForm = await this.page.locator('form[data-form="venue-create"], form[action*="venue"]').count() > 0; if (hasCreateForm) { console.log('āœ… Venue creation form found'); await this.captureEvidence('venue-create-form', 'Venue creation form available'); } // Test venue listing functionality const venueCount = await this.page.locator('.venue-item, .venue-row, [data-venue]').count(); console.log(`šŸ“‹ Found ${venueCount} venues in listing`); } else { console.log('āš ļø Venue Management page is empty or non-functional'); // Document the empty page if (venueManageResult.isEmpty) { console.log('šŸ“ Documenting empty Venue Management page'); } } return { venueList: venueListResult, venueManage: venueManageResult, functional: venueListResult.functional || venueManageResult.functional }; } catch (error) { console.error('āŒ Venue management testing failed:', error.message); await this.captureEvidence('venue-management-error', `Venue management error: ${error.message}`); return { success: false, error: error.message }; } } /** * Test organizer management functionality (if available) */ async testOrganizerManagement() { try { console.log('šŸ‘„ Testing Organizer Management Functionality'); // Test organizer management page (likely empty) const organizerResult = await this.navigateAndValidate({ url: '/trainer/organizer/manage/', name: 'Organizer Management', priority: 'HIGH' }); if (organizerResult.functional) { console.log('āœ… Organizer Management page is functional - testing features'); // Test organizer form functionality const hasCreateForm = await this.page.locator('form[data-form="organizer-create"], form[action*="organizer"]').count() > 0; if (hasCreateForm) { console.log('āœ… Organizer creation form found'); await this.captureEvidence('organizer-create-form', 'Organizer creation form available'); } // Test organizer listing const organizerCount = await this.page.locator('.organizer-item, .organizer-row, [data-organizer]').count(); console.log(`šŸ“‹ Found ${organizerCount} organizers in listing`); } else { console.log('āš ļø Organizer Management page is empty or non-functional'); } return { organizer: organizerResult, functional: organizerResult.functional }; } catch (error) { console.error('āŒ Organizer management testing failed:', error.message); await this.captureEvidence('organizer-management-error', `Organizer management error: ${error.message}`); return { success: false, error: error.message }; } } /** * Test profile management functionality */ async testProfileManagement() { try { console.log('šŸ‘¤ Testing Profile Management Functionality'); // Test profile view page const profileViewResult = await this.navigateAndValidate({ url: '/trainer/profile/view/', name: 'Profile View', priority: 'MEDIUM' }); // Test profile edit page const profileEditResult = await this.navigateAndValidate({ url: '/trainer/profile/edit/', name: 'Profile Edit', priority: 'HIGH' }); // Test training leads page (likely empty) const trainingLeadsResult = await this.navigateAndValidate({ url: '/trainer/profile/training-leads/', name: 'Training Leads Profile', priority: 'HIGH' }); // If profile edit is functional, test form functionality if (profileEditResult.functional) { console.log('āœ… Profile Edit page is functional - testing form features'); // Look for profile form fields const formFields = await this.page.locator('input, textarea, select').count(); console.log(`šŸ“ Found ${formFields} form fields on profile edit page`); // Check for specific trainer profile fields const trainerFields = [ 'input[name="trainer_name"], #trainer_name', 'textarea[name="trainer_bio"], #trainer_bio', 'input[name="trainer_email"], #trainer_email', 'input[name="trainer_phone"], #trainer_phone' ]; let fieldsFound = 0; for (const fieldSelector of trainerFields) { const fieldExists = await this.page.locator(fieldSelector).count() > 0; if (fieldExists) { fieldsFound++; console.log(`āœ… Profile field found: ${fieldSelector}`); } } console.log(`šŸ“‹ Profile form has ${fieldsFound}/${trainerFields.length} expected fields`); await this.captureEvidence('profile-edit-form', 'Profile edit form analysis complete'); } return { profileView: profileViewResult, profileEdit: profileEditResult, trainingLeads: trainingLeadsResult, functional: profileViewResult.functional || profileEditResult.functional }; } catch (error) { console.error('āŒ Profile management testing failed:', error.message); await this.captureEvidence('profile-management-error', `Profile management error: ${error.message}`); return { success: false, error: error.message }; } } /** * Test navigation consistency across all trainer pages */ async testNavigationConsistency() { try { console.log('🧭 Testing Navigation Consistency'); let navigationErrors = []; let commonNavigationElements = {}; // Analyze navigation on each functional page for (const result of this.navigationMatrix) { if (result.functional && !result.error) { try { // Navigate back to the page await this.page.goto(`https://upskill-staging.measurequick.com${result.page.url}`); // Check for common navigation elements const navElements = { breadcrumb: await this.page.locator('.hvac-breadcrumb, .breadcrumb').count() > 0, mainNav: await this.page.locator('.hvac-trainer-nav, .trainer-nav').count() > 0, userMenu: await this.page.locator('.user-menu, .trainer-menu').count() > 0, logoutLink: await this.page.locator('a[href*="logout"]').count() > 0 }; // Track common elements for (const [element, exists] of Object.entries(navElements)) { if (!commonNavigationElements[element]) { commonNavigationElements[element] = { count: 0, total: 0 }; } commonNavigationElements[element].total++; if (exists) { commonNavigationElements[element].count++; } } console.log(`šŸ” Navigation analysis for ${result.page.name}: ${Object.values(navElements).filter(Boolean).length}/4 elements found`); } catch (error) { navigationErrors.push({ page: result.page.name, error: error.message }); } } } // Calculate navigation consistency scores const consistencyScores = {}; for (const [element, data] of Object.entries(commonNavigationElements)) { consistencyScores[element] = data.total > 0 ? (data.count / data.total) * 100 : 0; } console.log('šŸ“Š Navigation Consistency Scores:'); for (const [element, score] of Object.entries(consistencyScores)) { console.log(` ${element}: ${score.toFixed(1)}%`); } await this.captureEvidence('navigation-consistency', 'Navigation consistency analysis complete'); return { consistencyScores, navigationErrors, elementsAnalyzed: Object.keys(commonNavigationElements).length }; } catch (error) { console.error('āŒ Navigation consistency testing failed:', error.message); return { success: false, error: error.message }; } } /** * Generate comprehensive test report */ generateTestReport() { const report = { testSuite: 'Trainer Management Comprehensive E2E Tests', execution: { startTime: new Date(this.testStartTime).toISOString(), endTime: new Date().toISOString(), duration: Date.now() - this.testStartTime, environment: 'staging' }, results: this.testResults, pagesTested: this.trainerPages.length, evidenceCollected: this.evidenceCollection.length, emptyPages: this.emptyPageDocumentation.length, navigationMatrix: this.navigationMatrix }; // High priority empty pages summary const highPriorityEmpty = this.emptyPageDocumentation.filter(page => page.page && page.page.priority === 'HIGH' ); if (highPriorityEmpty.length > 0) { report.criticalFindings = { highPriorityEmptyPages: highPriorityEmpty.map(page => ({ name: page.page?.name || 'Unknown', url: page.page?.url || 'Unknown', recommendation: `Implement ${page.page?.name || 'page'} functionality as specified in requirements` })) }; } return report; } } // Main Test Suite Implementation test.describe('Trainer Management Comprehensive E2E Tests', () => { let testSuite; let page; test.beforeAll(async () => { console.log('šŸš€ Starting Trainer Management Comprehensive Test Suite'); console.log('šŸ“‹ Testing Environment: https://upskill-staging.measurequick.com'); console.log('šŸ‘¤ Test Account: test_trainer'); }); test.beforeEach(async ({ page: testPage }, testInfo) => { page = testPage; testSuite = new TrainerManagementTestSuite(); // Set up test environment using base test setup await testSuite.setup(page, testInfo); // Authenticate as trainer console.log('šŸ” Authenticating as test trainer...'); await testSuite.authenticateAs(page, 'trainer'); // Verify authentication success const currentUrl = page.url(); if (!currentUrl.includes('/trainer/')) { throw new Error('Authentication failed - not redirected to trainer area'); } console.log('āœ… Authentication successful'); }); test.afterEach(async ({ page }, testInfo) => { if (testSuite) { await testSuite.teardown(page, testInfo); } }); test.afterAll(async () => { if (testSuite) { const report = testSuite.generateTestReport(); console.log('\nšŸ“Š TRAINER MANAGEMENT TEST SUMMARY'); console.log('====================================='); console.log(`Pages Tested: ${report.pagesTested}`); console.log(`Pages Accessible: ${report.results.pagesAccessible}`); console.log(`Pages Functional: ${report.results.pagesFunctional}`); console.log(`Pages Empty: ${report.results.pagesEmpty}`); console.log(`Errors Detected: ${report.results.errorsDetected}`); console.log(`Evidence Collected: ${report.evidenceCollected} screenshots`); if (report.criticalFindings && report.criticalFindings.highPriorityEmptyPages.length > 0) { console.log('\nšŸ”“ HIGH PRIORITY EMPTY PAGES:'); report.criticalFindings.highPriorityEmptyPages.forEach(page => { console.log(` - ${page.name} (${page.url})`); console.log(` Recommendation: ${page.recommendation}`); }); } console.log('\nšŸ“ Test artifacts saved in: ./test-results/screenshots/'); console.log('====================================='); } }); test('Phase 1: Authentication & Framework Integration', async () => { // Framework integration is tested in beforeEach expect(page.url()).toContain('/trainer/'); // Take evidence of successful authentication await testSuite.captureEvidence('authentication-success', 'Trainer authentication validated'); // Verify WordPress environment const errors = await testSuite.detectWordPressErrors(); expect(errors).toHaveLength(0); console.log('āœ… Phase 1 Complete: Authentication & Framework Integration'); }); test('Phase 2: Page Accessibility Matrix Testing', async () => { console.log('šŸ” Testing all 15 trainer pages for accessibility...'); const results = []; // Test each page systematically for (const pageInfo of testSuite.trainerPages) { const result = await testSuite.navigateAndValidate(pageInfo); results.push(result); // Small delay to avoid overwhelming the server await page.waitForTimeout(500); } // Validate results expect(results.length).toBe(15); const functionalPages = results.filter(r => r.functional).length; const emptyPages = results.filter(r => r.isEmpty).length; console.log(`šŸ“Š Page Accessibility Results: ${functionalPages} functional, ${emptyPages} empty`); // High priority pages should be functional or properly documented if empty const highPriorityPages = results.filter(r => r.page.priority === 'HIGH'); const highPriorityEmpty = highPriorityPages.filter(r => r.isEmpty); if (highPriorityEmpty.length > 0) { console.log(`āš ļø Found ${highPriorityEmpty.length} high-priority empty pages - documented for development`); } console.log('āœ… Phase 2 Complete: Page Accessibility Matrix Testing'); }); test('Phase 3: Dashboard Comprehensive Testing', async () => { const dashboardResults = await testSuite.testDashboardFunctionality(); expect(dashboardResults.success).toBe(true); if (dashboardResults.stats) { console.log('šŸ“ˆ Dashboard statistics captured successfully'); } if (dashboardResults.responsiveness) { console.log('šŸ“± Mobile responsiveness validated'); } console.log('āœ… Phase 3 Complete: Dashboard Comprehensive Testing'); }); test('Phase 4: Venue Management Testing', async () => { const venueResults = await testSuite.testVenueManagement(); // Venue management may be empty - document findings if (venueResults.functional) { console.log('āœ… Venue management functionality is available'); } else { console.log('šŸ“ Venue management functionality documented as empty/non-functional'); } console.log('āœ… Phase 4 Complete: Venue Management Testing'); }); test('Phase 5: Organizer Management Testing', async () => { const organizerResults = await testSuite.testOrganizerManagement(); // Organizer management may be empty - document findings if (organizerResults.functional) { console.log('āœ… Organizer management functionality is available'); } else { console.log('šŸ“ Organizer management functionality documented as empty/non-functional'); } console.log('āœ… Phase 5 Complete: Organizer Management Testing'); }); test('Phase 6: Profile Management Testing', async () => { const profileResults = await testSuite.testProfileManagement(); expect(profileResults.functional).toBe(true); // At least one of the profile pages should be functional const functionalProfilePages = [ profileResults.profileView?.functional, profileResults.profileEdit?.functional ].filter(Boolean).length; expect(functionalProfilePages).toBeGreaterThan(0); console.log('āœ… Phase 6 Complete: Profile Management Testing'); }); test('Phase 7: Navigation Consistency & Workflow Testing', async () => { const navigationResults = await testSuite.testNavigationConsistency(); if (navigationResults.consistencyScores) { // At least 50% consistency expected for main navigation elements const mainNavScore = navigationResults.consistencyScores.mainNav || 0; console.log(`🧭 Main navigation consistency: ${mainNavScore.toFixed(1)}%`); if (mainNavScore < 50) { console.log('āš ļø Low navigation consistency detected - documented for improvement'); } } if (navigationResults.navigationErrors && navigationResults.navigationErrors.length > 0) { console.log(`āš ļø Navigation errors found: ${navigationResults.navigationErrors.length}`); } console.log('āœ… Phase 7 Complete: Navigation Consistency & Workflow Testing'); }); test('Phase 8: Evidence Collection & Final Validation', async () => { // Final evidence collection await testSuite.captureEvidence('test-suite-complete', 'All trainer management tests completed'); // Generate and validate comprehensive report const finalReport = testSuite.generateTestReport(); expect(finalReport.pagesTested).toBe(15); expect(finalReport.evidenceCollected).toBeGreaterThan(10); // Validate test coverage const coveragePercentage = (finalReport.results.pagesAccessible / finalReport.pagesTested) * 100; console.log(`šŸ“ˆ Test Coverage: ${coveragePercentage.toFixed(1)}%`); expect(coveragePercentage).toBeGreaterThan(80); // At least 80% of pages should be accessible console.log('āœ… Phase 8 Complete: Evidence Collection & Final Validation'); console.log('šŸŽ‰ TRAINER MANAGEMENT COMPREHENSIVE E2E TESTING COMPLETE'); }); }); module.exports = TrainerManagementTestSuite;