- Created admin page for direct event seeding (admin/seed-events-direct.php)
- Added test admin user creation script with master trainer roles
- Implemented comprehensive Playwright tests for event edit workflow
- Verified field population with TEC v5.0.8
- Confirmed 11 core fields properly populate in edit forms
- Added XWayland display configuration for headed browser testing
- Created seeding scripts that add events with complete metadata
Test Results:
- Login functionality: Working
- Event access: 20+ events accessible
- Field population: 11 essential fields confirmed
- Edit workflow: Functional with TEC Community Events
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
		
	
			
		
			
				
	
	
		
			503 lines
		
	
	
		
			No EOL
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			503 lines
		
	
	
		
			No EOL
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable file
		
	
	
	
	
| #!/usr/bin/env node
 | ||
| 
 | ||
| /**
 | ||
|  * Comprehensive E2E Test for HVAC Event Edit Functionality
 | ||
|  * Tests complete event creation, editing, and field population
 | ||
|  * 
 | ||
|  * @package HVAC_Community_Events
 | ||
|  * @version 2.0.0
 | ||
|  */
 | ||
| 
 | ||
| const { chromium } = require('@playwright/test');
 | ||
| const fs = require('fs').promises;
 | ||
| const path = require('path');
 | ||
| 
 | ||
| // Configuration
 | ||
| const CONFIG = {
 | ||
|     baseUrl: 'https://upskill-staging.measurequick.com',
 | ||
|     credentials: {
 | ||
|         trainer: {
 | ||
|             email: 'test_trainer@example.com',
 | ||
|             password: 'TestTrainer123!'
 | ||
|         },
 | ||
|         master: {
 | ||
|             email: 'test_master@example.com',
 | ||
|             password: 'TestMaster123!'
 | ||
|         },
 | ||
|         admin: {
 | ||
|             email: 'ben@upskillhvac.com',
 | ||
|             password: process.env.ADMIN_PASSWORD || ''
 | ||
|         }
 | ||
|     },
 | ||
|     screenshotDir: 'screenshots/e2e-test',
 | ||
|     timeout: 60000
 | ||
| };
 | ||
| 
 | ||
| // Test data
 | ||
| const TEST_EVENT = {
 | ||
|     title: `E2E Test Event ${Date.now()}`,
 | ||
|     description: 'This is a comprehensive E2E test event for verifying all functionality.',
 | ||
|     venue: 'Dallas Training Center',
 | ||
|     organizer: 'HVAC Training Solutions',
 | ||
|     cost: '399',
 | ||
|     startDate: '2025-09-01',
 | ||
|     endDate: '2025-09-02',
 | ||
|     startTime: '09:00',
 | ||
|     endTime: '17:00',
 | ||
|     website: 'https://example.com/test-event',
 | ||
|     maxAttendees: '30'
 | ||
| };
 | ||
| 
 | ||
| // Test results tracking
 | ||
| const RESULTS = {
 | ||
|     startTime: Date.now(),
 | ||
|     tests: [],
 | ||
|     passed: 0,
 | ||
|     failed: 0,
 | ||
|     screenshots: []
 | ||
| };
 | ||
| 
 | ||
| // Helper functions
 | ||
| async function takeScreenshot(page, name) {
 | ||
|     try {
 | ||
|         await fs.mkdir(CONFIG.screenshotDir, { recursive: true });
 | ||
|         const filename = `${name}-${Date.now()}.png`;
 | ||
|         const filepath = path.join(CONFIG.screenshotDir, filename);
 | ||
|         await page.screenshot({ path: filepath, fullPage: true });
 | ||
|         RESULTS.screenshots.push(filepath);
 | ||
|         console.log(`📸 Screenshot: ${filename}`);
 | ||
|         return filepath;
 | ||
|     } catch (error) {
 | ||
|         console.log(`⚠️ Screenshot failed: ${error.message}`);
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| async function logTest(name, status, details = '') {
 | ||
|     const icon = status === 'passed' ? '✅' : '❌';
 | ||
|     console.log(`${icon} ${name}: ${status.toUpperCase()} ${details}`);
 | ||
|     
 | ||
|     RESULTS.tests.push({ name, status, details, timestamp: Date.now() });
 | ||
|     if (status === 'passed') {
 | ||
|         RESULTS.passed++;
 | ||
|     } else {
 | ||
|         RESULTS.failed++;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| async function login(page, credentials) {
 | ||
|     try {
 | ||
|         console.log('\n🔐 Logging in...');
 | ||
|         await page.goto(`${CONFIG.baseUrl}/wp-login.php`);
 | ||
|         await page.fill('#user_login', credentials.email);
 | ||
|         await page.fill('#user_pass', credentials.password);
 | ||
|         await page.click('#wp-submit');
 | ||
|         
 | ||
|         // Wait for redirect
 | ||
|         await page.waitForURL(url => {
 | ||
|             const urlString = typeof url === 'string' ? url : url.toString();
 | ||
|             return !urlString.includes('wp-login');
 | ||
|         }, { timeout: 10000 });
 | ||
|         
 | ||
|         const currentUrl = page.url();
 | ||
|         if (currentUrl.includes('dashboard') || currentUrl.includes('admin')) {
 | ||
|             await logTest('Login', 'passed', credentials.email);
 | ||
|             return true;
 | ||
|         } else {
 | ||
|             await logTest('Login', 'failed', 'Unexpected redirect');
 | ||
|             return false;
 | ||
|         }
 | ||
|     } catch (error) {
 | ||
|         await logTest('Login', 'failed', error.message);
 | ||
|         return false;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| async function testWordPressAdmin(page) {
 | ||
|     console.log('\n📊 Testing WordPress Admin Event Management...');
 | ||
|     
 | ||
|     try {
 | ||
|         // Navigate to events list
 | ||
|         await page.goto(`${CONFIG.baseUrl}/wp-admin/edit.php?post_type=tribe_events`);
 | ||
|         await page.waitForLoadState('domcontentloaded');
 | ||
|         
 | ||
|         await takeScreenshot(page, 'admin-events-list');
 | ||
|         
 | ||
|         // Count existing events
 | ||
|         const eventRows = await page.$$('tbody#the-list tr');
 | ||
|         console.log(`Found ${eventRows.length} existing events`);
 | ||
|         
 | ||
|         if (eventRows.length > 0) {
 | ||
|             await logTest('Admin Events List', 'passed', `${eventRows.length} events found`);
 | ||
|             
 | ||
|             // Test editing first event
 | ||
|             const editLink = await page.$('tbody#the-list tr:first-child .row-actions .edit a');
 | ||
|             if (editLink) {
 | ||
|                 await editLink.click();
 | ||
|                 await page.waitForLoadState('networkidle');
 | ||
|                 
 | ||
|                 await takeScreenshot(page, 'admin-edit-form');
 | ||
|                 
 | ||
|                 // Check if fields are populated
 | ||
|                 const titleField = await page.$('#title');
 | ||
|                 if (titleField) {
 | ||
|                     const currentTitle = await titleField.inputValue();
 | ||
|                     console.log(`Current title: ${currentTitle}`);
 | ||
|                     
 | ||
|                     // Update title
 | ||
|                     const newTitle = currentTitle + ' (Updated E2E)';
 | ||
|                     await titleField.fill(newTitle);
 | ||
|                     
 | ||
|                     // Check other fields
 | ||
|                     const fields = {
 | ||
|                         'Start Date': '#EventStartDate',
 | ||
|                         'End Date': '#EventEndDate',
 | ||
|                         'Cost': '#EventCost',
 | ||
|                         'Venue': '#venue-name, select[name="venue[VenueID]"]'
 | ||
|                     };
 | ||
|                     
 | ||
|                     for (const [name, selector] of Object.entries(fields)) {
 | ||
|                         const field = await page.$(selector);
 | ||
|                         if (field) {
 | ||
|                             const value = await field.inputValue().catch(() => '');
 | ||
|                             console.log(`  ${name}: ${value || 'N/A'}`);
 | ||
|                         }
 | ||
|                     }
 | ||
|                     
 | ||
|                     // Save changes
 | ||
|                     const updateButton = await page.$('#publish');
 | ||
|                     if (updateButton) {
 | ||
|                         await updateButton.click();
 | ||
|                         await page.waitForSelector('.notice-success, .updated', { timeout: 10000 });
 | ||
|                         
 | ||
|                         await takeScreenshot(page, 'admin-updated');
 | ||
|                         await logTest('Admin Event Edit', 'passed', 'Event updated successfully');
 | ||
|                     }
 | ||
|                 } else {
 | ||
|                     await logTest('Admin Event Edit', 'failed', 'Title field not found');
 | ||
|                 }
 | ||
|             }
 | ||
|         } else {
 | ||
|             await logTest('Admin Events List', 'failed', 'No events found');
 | ||
|         }
 | ||
|         
 | ||
|         // Test creating new event
 | ||
|         console.log('\n📝 Testing event creation in admin...');
 | ||
|         await page.goto(`${CONFIG.baseUrl}/wp-admin/post-new.php?post_type=tribe_events`);
 | ||
|         await page.waitForLoadState('domcontentloaded');
 | ||
|         
 | ||
|         await takeScreenshot(page, 'admin-new-event');
 | ||
|         
 | ||
|         // Fill new event form
 | ||
|         const titleField = await page.$('#title');
 | ||
|         if (titleField) {
 | ||
|             await titleField.fill(TEST_EVENT.title);
 | ||
|             
 | ||
|             // Fill description
 | ||
|             const contentFrame = await page.$('#content_ifr');
 | ||
|             if (contentFrame) {
 | ||
|                 const frame = await contentFrame.contentFrame();
 | ||
|                 await frame.fill('#tinymce', TEST_EVENT.description);
 | ||
|             } else {
 | ||
|                 const contentArea = await page.$('#content');
 | ||
|                 if (contentArea) {
 | ||
|                     await contentArea.fill(TEST_EVENT.description);
 | ||
|                 }
 | ||
|             }
 | ||
|             
 | ||
|             // Set dates
 | ||
|             const startDate = await page.$('#EventStartDate');
 | ||
|             if (startDate) await startDate.fill(TEST_EVENT.startDate);
 | ||
|             
 | ||
|             const endDate = await page.$('#EventEndDate');
 | ||
|             if (endDate) await endDate.fill(TEST_EVENT.endDate);
 | ||
|             
 | ||
|             // Set cost
 | ||
|             const cost = await page.$('#EventCost');
 | ||
|             if (cost) await cost.fill(TEST_EVENT.cost);
 | ||
|             
 | ||
|             // Publish
 | ||
|             const publishButton = await page.$('#publish');
 | ||
|             if (publishButton) {
 | ||
|                 await publishButton.click();
 | ||
|                 await page.waitForSelector('.notice-success, .updated', { timeout: 10000 });
 | ||
|                 
 | ||
|                 await takeScreenshot(page, 'admin-created');
 | ||
|                 await logTest('Admin Event Creation', 'passed', 'New event created');
 | ||
|             }
 | ||
|         } else {
 | ||
|             await logTest('Admin Event Creation', 'failed', 'Form fields not found');
 | ||
|         }
 | ||
|         
 | ||
|     } catch (error) {
 | ||
|         await logTest('WordPress Admin Test', 'failed', error.message);
 | ||
|         await takeScreenshot(page, 'admin-error');
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| async function testTrainerPages(page) {
 | ||
|     console.log('\n🎯 Testing HVAC Trainer Event Pages...');
 | ||
|     
 | ||
|     try {
 | ||
|         // Navigate to trainer dashboard
 | ||
|         await page.goto(`${CONFIG.baseUrl}/trainer/dashboard/`);
 | ||
|         await page.waitForLoadState('domcontentloaded');
 | ||
|         
 | ||
|         await takeScreenshot(page, 'trainer-dashboard');
 | ||
|         
 | ||
|         const dashboardVisible = await page.locator('.hvac-dashboard-header, h1').first().isVisible();
 | ||
|         if (dashboardVisible) {
 | ||
|             await logTest('Trainer Dashboard', 'passed');
 | ||
|         } else {
 | ||
|             await logTest('Trainer Dashboard', 'failed', 'Dashboard not visible');
 | ||
|         }
 | ||
|         
 | ||
|         // Test events list
 | ||
|         await page.goto(`${CONFIG.baseUrl}/trainer/events/`);
 | ||
|         await page.waitForLoadState('domcontentloaded');
 | ||
|         
 | ||
|         await takeScreenshot(page, 'trainer-events-list');
 | ||
|         
 | ||
|         // Check page content
 | ||
|         const pageContent = await page.locator('body').textContent();
 | ||
|         
 | ||
|         if (pageContent.includes('404')) {
 | ||
|             await logTest('Trainer Events List', 'failed', '404 error');
 | ||
|         } else if (pageContent.includes('event') || pageContent.includes('Event')) {
 | ||
|             await logTest('Trainer Events List', 'passed');
 | ||
|             
 | ||
|             // Look for edit links
 | ||
|             const editLinks = await page.$$('a[href*="edit"]');
 | ||
|             if (editLinks.length > 0) {
 | ||
|                 console.log(`Found ${editLinks.length} edit links`);
 | ||
|                 
 | ||
|                 // Click first edit link
 | ||
|                 await editLinks[0].click();
 | ||
|                 await page.waitForLoadState('networkidle');
 | ||
|                 
 | ||
|                 await takeScreenshot(page, 'trainer-edit-page');
 | ||
|                 
 | ||
|                 // Check if on edit page
 | ||
|                 const editPageContent = await page.locator('body').textContent();
 | ||
|                 if (editPageContent.includes('Edit') || editPageContent.includes('Update')) {
 | ||
|                     await logTest('Trainer Event Edit Page', 'passed');
 | ||
|                 } else {
 | ||
|                     await logTest('Trainer Event Edit Page', 'failed', 'Edit form not found');
 | ||
|                 }
 | ||
|             }
 | ||
|         } else {
 | ||
|             await logTest('Trainer Events List', 'failed', 'No event content');
 | ||
|         }
 | ||
|         
 | ||
|         // Test event creation page
 | ||
|         await page.goto(`${CONFIG.baseUrl}/trainer/events/create/`);
 | ||
|         await page.waitForLoadState('domcontentloaded');
 | ||
|         
 | ||
|         await takeScreenshot(page, 'trainer-create-page');
 | ||
|         
 | ||
|         const createPageContent = await page.locator('body').textContent();
 | ||
|         if (createPageContent.includes('404')) {
 | ||
|             await logTest('Trainer Create Event Page', 'failed', '404 error');
 | ||
|         } else {
 | ||
|             await logTest('Trainer Create Event Page', 'passed');
 | ||
|         }
 | ||
|         
 | ||
|     } catch (error) {
 | ||
|         await logTest('Trainer Pages Test', 'failed', error.message);
 | ||
|         await takeScreenshot(page, 'trainer-error');
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| async function testCommunityPages(page) {
 | ||
|     console.log('\n🌐 Testing TEC Community Pages...');
 | ||
|     
 | ||
|     const communityUrls = [
 | ||
|         '/community/',
 | ||
|         '/community/add/',
 | ||
|         '/community/list/',
 | ||
|         '/events/community/',
 | ||
|         '/events/community/add/',
 | ||
|         '/events/community/list/'
 | ||
|     ];
 | ||
|     
 | ||
|     for (const url of communityUrls) {
 | ||
|         try {
 | ||
|             await page.goto(`${CONFIG.baseUrl}${url}`);
 | ||
|             await page.waitForLoadState('domcontentloaded');
 | ||
|             
 | ||
|             const content = await page.locator('body').textContent();
 | ||
|             
 | ||
|             if (content.includes('404') || content.includes('not found')) {
 | ||
|                 await logTest(`Community ${url}`, 'failed', '404');
 | ||
|             } else if (content.includes('login') || content.includes('Login')) {
 | ||
|                 await logTest(`Community ${url}`, 'failed', 'Login required');
 | ||
|             } else {
 | ||
|                 await logTest(`Community ${url}`, 'passed');
 | ||
|             }
 | ||
|         } catch (error) {
 | ||
|             await logTest(`Community ${url}`, 'failed', error.message);
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| async function generateReport() {
 | ||
|     const duration = ((Date.now() - RESULTS.startTime) / 1000).toFixed(1);
 | ||
|     const successRate = RESULTS.tests.length > 0 
 | ||
|         ? ((RESULTS.passed / RESULTS.tests.length) * 100).toFixed(1)
 | ||
|         : 0;
 | ||
|     
 | ||
|     let report = `# HVAC Event Edit E2E Test Report\n\n`;
 | ||
|     report += `**Date:** ${new Date().toISOString()}\n`;
 | ||
|     report += `**Environment:** ${CONFIG.baseUrl}\n`;
 | ||
|     report += `**Duration:** ${duration} seconds\n\n`;
 | ||
|     
 | ||
|     report += `## Summary\n\n`;
 | ||
|     report += `- **Total Tests:** ${RESULTS.tests.length}\n`;
 | ||
|     report += `- **Passed:** ${RESULTS.passed} ✅\n`;
 | ||
|     report += `- **Failed:** ${RESULTS.failed} ❌\n`;
 | ||
|     report += `- **Success Rate:** ${successRate}%\n\n`;
 | ||
|     
 | ||
|     report += `## Test Results\n\n`;
 | ||
|     report += `| Test | Status | Details |\n`;
 | ||
|     report += `|------|--------|---------|\n`;
 | ||
|     
 | ||
|     for (const test of RESULTS.tests) {
 | ||
|         const icon = test.status === 'passed' ? '✅' : '❌';
 | ||
|         report += `| ${test.name} | ${icon} ${test.status} | ${test.details} |\n`;
 | ||
|     }
 | ||
|     
 | ||
|     report += `\n## Screenshots\n\n`;
 | ||
|     report += `${RESULTS.screenshots.length} screenshots captured:\n\n`;
 | ||
|     for (const screenshot of RESULTS.screenshots) {
 | ||
|         report += `- ${path.basename(screenshot)}\n`;
 | ||
|     }
 | ||
|     
 | ||
|     report += `\n## Assessment\n\n`;
 | ||
|     
 | ||
|     if (successRate >= 80) {
 | ||
|         report += `### ✅ SYSTEM READY\n\n`;
 | ||
|         report += `The event editing functionality is working well with ${successRate}% success rate.\n`;
 | ||
|     } else if (successRate >= 60) {
 | ||
|         report += `### ⚠️ PARTIAL FUNCTIONALITY\n\n`;
 | ||
|         report += `Some features are working but improvements needed. Success rate: ${successRate}%\n`;
 | ||
|     } else {
 | ||
|         report += `### ❌ NEEDS ATTENTION\n\n`;
 | ||
|         report += `Significant issues detected. Success rate: ${successRate}%\n`;
 | ||
|     }
 | ||
|     
 | ||
|     // Save report
 | ||
|     await fs.mkdir('reports', { recursive: true });
 | ||
|     const reportFile = `reports/e2e-test-report-${Date.now()}.md`;
 | ||
|     await fs.writeFile(reportFile, report);
 | ||
|     
 | ||
|     return { reportFile, successRate };
 | ||
| }
 | ||
| 
 | ||
| // Main test execution
 | ||
| async function runFullE2ETest() {
 | ||
|     console.log('🚀 HVAC EVENT EDIT FULL E2E TEST');
 | ||
|     console.log('═'.repeat(60));
 | ||
|     console.log(`Environment: ${CONFIG.baseUrl}`);
 | ||
|     console.log(`Time: ${new Date().toLocaleString()}`);
 | ||
|     console.log('═'.repeat(60));
 | ||
|     
 | ||
|     const browser = await chromium.launch({ 
 | ||
|         headless: true,
 | ||
|         timeout: CONFIG.timeout 
 | ||
|     });
 | ||
|     
 | ||
|     const context = await browser.newContext({
 | ||
|         viewport: { width: 1280, height: 720 }
 | ||
|     });
 | ||
|     
 | ||
|     const page = await context.newPage();
 | ||
|     
 | ||
|     try {
 | ||
|         // Test 1: Admin functionality (if password provided)
 | ||
|         if (CONFIG.credentials.admin.password) {
 | ||
|             console.log('\n👤 Testing with Admin Account...');
 | ||
|             if (await login(page, CONFIG.credentials.admin)) {
 | ||
|                 await testWordPressAdmin(page);
 | ||
|             }
 | ||
|         } else {
 | ||
|             console.log('\n⚠️ Skipping admin tests (no password provided)');
 | ||
|         }
 | ||
|         
 | ||
|         // Test 2: Trainer functionality
 | ||
|         console.log('\n👤 Testing with Trainer Account...');
 | ||
|         if (await login(page, CONFIG.credentials.trainer)) {
 | ||
|             await testTrainerPages(page);
 | ||
|             await testCommunityPages(page);
 | ||
|         }
 | ||
|         
 | ||
|         // Test 3: Master trainer functionality
 | ||
|         console.log('\n👤 Testing with Master Trainer Account...');
 | ||
|         if (await login(page, CONFIG.credentials.master)) {
 | ||
|             await testTrainerPages(page);
 | ||
|         }
 | ||
|         
 | ||
|     } catch (error) {
 | ||
|         console.error('\n❌ Fatal error:', error.message);
 | ||
|         await takeScreenshot(page, 'fatal-error');
 | ||
|     } finally {
 | ||
|         await browser.close();
 | ||
|     }
 | ||
|     
 | ||
|     // Generate final report
 | ||
|     console.log('\n' + '═'.repeat(60));
 | ||
|     console.log('📊 GENERATING FINAL REPORT');
 | ||
|     console.log('═'.repeat(60));
 | ||
|     
 | ||
|     const { reportFile, successRate } = await generateReport();
 | ||
|     
 | ||
|     console.log(`\nTotal Tests: ${RESULTS.tests.length}`);
 | ||
|     console.log(`✅ Passed: ${RESULTS.passed}`);
 | ||
|     console.log(`❌ Failed: ${RESULTS.failed}`);
 | ||
|     console.log(`Success Rate: ${successRate}%`);
 | ||
|     
 | ||
|     console.log(`\n📄 Full report: ${reportFile}`);
 | ||
|     console.log(`📸 Screenshots: ${CONFIG.screenshotDir}/`);
 | ||
|     
 | ||
|     if (successRate >= 80) {
 | ||
|         console.log('\n🎉 EVENT EDITING FUNCTIONALITY VERIFIED!');
 | ||
|     } else if (successRate >= 60) {
 | ||
|         console.log('\n⚠️ PARTIAL SUCCESS - Some features need attention');
 | ||
|     } else {
 | ||
|         console.log('\n❌ SIGNIFICANT ISSUES - Review needed');
 | ||
|     }
 | ||
|     
 | ||
|     console.log('═'.repeat(60));
 | ||
|     
 | ||
|     process.exit(RESULTS.failed > 3 ? 1 : 0);
 | ||
| }
 | ||
| 
 | ||
| // Handle command line arguments
 | ||
| const args = process.argv.slice(2);
 | ||
| if (args.includes('--help')) {
 | ||
|     console.log(`
 | ||
| HVAC Event Edit E2E Test
 | ||
| 
 | ||
| Usage: node test-full-event-e2e.js [options]
 | ||
| 
 | ||
| Options:
 | ||
|   --admin-pass PASSWORD   Admin password for full testing
 | ||
|   --help                  Show this help message
 | ||
| 
 | ||
| Examples:
 | ||
|   node test-full-event-e2e.js
 | ||
|   node test-full-event-e2e.js --admin-pass MyPassword123
 | ||
|   ADMIN_PASSWORD=MyPassword123 node test-full-event-e2e.js
 | ||
|     `);
 | ||
|     process.exit(0);
 | ||
| }
 | ||
| 
 | ||
| // Check for admin password in arguments
 | ||
| const passIndex = args.indexOf('--admin-pass');
 | ||
| if (passIndex !== -1 && args[passIndex + 1]) {
 | ||
|     CONFIG.credentials.admin.password = args[passIndex + 1];
 | ||
| }
 | ||
| 
 | ||
| // Run the tests
 | ||
| runFullE2ETest().catch(error => {
 | ||
|     console.error('Test execution failed:', error);
 | ||
|     process.exit(1);
 | ||
| }); |