#!/usr/bin/env node /** * Complete Event Edit Workflow Test * Tests the FULL edit cycle: access, populate, edit, save, verify */ const { chromium } = require('@playwright/test'); const fs = require('fs').promises; const CONFIG = { baseUrl: 'https://upskill-staging.measurequick.com', credentials: { email: 'test_trainer@example.com', password: 'TestTrainer123!' } }; // Track field values before and after const FIELD_VALUES = { before: {}, after: {}, changes: {} }; async function screenshot(page, name) { await fs.mkdir('screenshots/edit-workflow', { recursive: true }); const path = `screenshots/edit-workflow/${name}-${Date.now()}.png`; await page.screenshot({ path, fullPage: true }); console.log(`šŸ“ø Screenshot: ${name}`); return path; } async function createTestEvent(page) { console.log('\nšŸ“ Creating test event via WordPress Admin...'); await page.goto(`${CONFIG.baseUrl}/wp-admin/post-new.php?post_type=tribe_events`); await page.waitForLoadState('domcontentloaded'); // Fill basic event data const eventData = { title: `Test Event for Edit Verification ${Date.now()}`, description: 'This event will be edited to verify all fields save correctly.', startDate: '2025-09-15', endDate: '2025-09-16', startTime: '09:00', endTime: '17:00', cost: '299', venue: 'Test Venue', organizer: 'Test Organizer', website: 'https://example.com/test' }; // Title const titleField = await page.$('#title'); if (titleField) { await titleField.fill(eventData.title); console.log('āœ… Title set'); } // Description (try different methods) const contentFrame = await page.$('#content_ifr'); if (contentFrame) { const frame = await contentFrame.contentFrame(); await frame.fill('#tinymce', eventData.description); console.log('āœ… Description set (TinyMCE)'); } else { const contentArea = await page.$('#content'); if (contentArea) { await contentArea.fill(eventData.description); console.log('āœ… Description set (textarea)'); } } // Dates const startDate = await page.$('#EventStartDate'); if (startDate) { await startDate.fill(eventData.startDate); console.log('āœ… Start date set'); } const endDate = await page.$('#EventEndDate'); if (endDate) { await endDate.fill(eventData.endDate); console.log('āœ… End date set'); } // Times const startTime = await page.$('#EventStartTime'); if (startTime) { await startTime.fill(eventData.startTime); console.log('āœ… Start time set'); } const endTime = await page.$('#EventEndTime'); if (endTime) { await endTime.fill(eventData.endTime); console.log('āœ… End time set'); } // Cost const costField = await page.$('#EventCost'); if (costField) { await costField.fill(eventData.cost); console.log('āœ… Cost set'); } // Website const urlField = await page.$('#EventURL'); if (urlField) { await urlField.fill(eventData.website); console.log('āœ… Website set'); } // Save as draft first const saveDraft = await page.$('#save-post'); if (saveDraft) { await saveDraft.click(); await page.waitForSelector('.notice-success, #message', { timeout: 10000 }); console.log('āœ… Event saved as draft'); } // Now publish const publishBtn = await page.$('#publish'); if (publishBtn) { await publishBtn.click(); await page.waitForSelector('.notice-success, #message', { timeout: 10000 }); console.log('āœ… Event published'); } // Get the event ID from URL const url = page.url(); const match = url.match(/post=(\d+)/); const eventId = match ? match[1] : null; console.log(`āœ… Event created with ID: ${eventId}`); return eventId; } async function accessEventFromDashboard(page) { console.log('\nšŸ” Accessing event from dashboard...'); // Go to events list await page.goto(`${CONFIG.baseUrl}/trainer/events/`); await page.waitForLoadState('domcontentloaded'); await screenshot(page, 'events-list'); // Try multiple selectors for edit links const editSelectors = [ 'a[href*="action=edit"]', 'a[href*="/edit/"]', '.edit-link', 'a:has-text("Edit")', 'button:has-text("Edit")' ]; let editLink = null; for (const selector of editSelectors) { editLink = await page.$(selector); if (editLink) { console.log(`āœ… Found edit link with selector: ${selector}`); break; } } if (!editLink) { // If no edit links, go directly to admin console.log('āš ļø No edit links found on trainer page, using admin...'); await page.goto(`${CONFIG.baseUrl}/wp-admin/edit.php?post_type=tribe_events`); const firstEdit = await page.$('#the-list .row-actions .edit a'); if (firstEdit) { await firstEdit.click(); await page.waitForLoadState('networkidle'); return true; } return false; } await editLink.click(); await page.waitForLoadState('networkidle'); return true; } async function captureAllFields(page) { console.log('\nšŸ“Š Capturing all field values...'); const fields = {}; // Define all TEC fields to check const fieldSelectors = { 'title': '#title, input[name="post_title"]', 'content': '#content, #tinymce', 'startDate': '#EventStartDate, input[name="EventStartDate"]', 'endDate': '#EventEndDate, input[name="EventEndDate"]', 'startTime': '#EventStartTime, input[name="EventStartTime"]', 'endTime': '#EventEndTime, input[name="EventEndTime"]', 'allDay': '#EventAllDay, input[name="EventAllDay"]', 'timezone': '#event-timezone, select[name="EventTimezone"]', 'cost': '#EventCost, input[name="EventCost"]', 'currency': '#EventCurrencySymbol, input[name="EventCurrencySymbol"]', 'website': '#EventURL, input[name="EventURL"]', 'venue': '#venue-name, select[name="venue[VenueID]"], input[name="venue[Venue]"]', 'address': '#VenueAddress, input[name="venue[Address]"]', 'city': '#VenueCity, input[name="venue[City]"]', 'state': '#VenueState, input[name="venue[State]"]', 'zip': '#VenueZip, input[name="venue[Zip]"]', 'country': '#VenueCountry, select[name="venue[Country]"]', 'phone': '#VenuePhone, input[name="venue[Phone]"]', 'organizer': '#organizer-name, select[name="organizer[OrganizerID]"], input[name="organizer[Organizer]"]', 'organizerEmail': '#OrganizerEmail, input[name="organizer[Email]"]', 'organizerPhone': '#OrganizerPhone, input[name="organizer[Phone]"]', 'organizerWebsite': '#OrganizerWebsite, input[name="organizer[Website]"]' }; for (const [fieldName, selector] of Object.entries(fieldSelectors)) { try { const element = await page.$(selector); if (element) { // Try different methods to get value let value = await element.inputValue().catch(() => null); if (!value) { value = await element.textContent().catch(() => null); } if (!value) { value = await element.evaluate(el => { if (el.tagName === 'SELECT') { return el.options[el.selectedIndex]?.text || ''; } return el.value || el.innerText || ''; }); } if (value) { fields[fieldName] = value; console.log(` ${fieldName}: ${value.substring(0, 50)}${value.length > 50 ? '...' : ''}`); } } else { console.log(` ${fieldName}: [field not found]`); } } catch (error) { console.log(` ${fieldName}: [error reading]`); } } // Check for TinyMCE content const contentFrame = await page.$('#content_ifr'); if (contentFrame && !fields.content) { try { const frame = await contentFrame.contentFrame(); const content = await frame.$eval('#tinymce', el => el.textContent); if (content) { fields.content = content; console.log(` content (TinyMCE): ${content.substring(0, 50)}...`); } } catch (error) { console.log(' content: [TinyMCE error]'); } } await screenshot(page, 'fields-captured'); return fields; } async function editFields(page, originalValues) { console.log('\nāœļø Editing fields...'); const changes = {}; // Edit title const titleField = await page.$('#title'); if (titleField && originalValues.title) { const newTitle = originalValues.title + ' (EDITED)'; await titleField.fill(newTitle); changes.title = newTitle; console.log('āœ… Title edited'); } // Edit cost const costField = await page.$('#EventCost'); if (costField && originalValues.cost) { const newCost = '399'; await costField.fill(newCost); changes.cost = newCost; console.log('āœ… Cost edited'); } // Edit start date const startDateField = await page.$('#EventStartDate'); if (startDateField && originalValues.startDate) { const newDate = '2025-10-01'; await startDateField.fill(newDate); changes.startDate = newDate; console.log('āœ… Start date edited'); } // Edit website const urlField = await page.$('#EventURL'); if (urlField) { const newUrl = 'https://edited.example.com/event'; await urlField.fill(newUrl); changes.website = newUrl; console.log('āœ… Website edited'); } // Edit description const contentFrame = await page.$('#content_ifr'); if (contentFrame) { try { const frame = await contentFrame.contentFrame(); const tinymce = await frame.$('#tinymce'); if (tinymce) { await tinymce.fill('EDITED: This event description has been updated.'); changes.content = 'EDITED: This event description has been updated.'; console.log('āœ… Description edited'); } } catch (error) { // Try textarea const contentArea = await page.$('#content'); if (contentArea) { await contentArea.fill('EDITED: This event description has been updated.'); changes.content = 'EDITED: This event description has been updated.'; console.log('āœ… Description edited (textarea)'); } } } await screenshot(page, 'fields-edited'); return changes; } async function saveAndVerify(page, expectedChanges) { console.log('\nšŸ’¾ Saving changes...'); // Find and click update/publish button const updateBtn = await page.$('#publish, #save-post, input[name="save"]'); if (updateBtn) { await updateBtn.click(); // Wait for success message await page.waitForSelector('.notice-success, #message, .updated', { timeout: 10000 }); console.log('āœ… Changes saved'); await screenshot(page, 'saved-success'); } else { console.log('āŒ Save button not found'); return false; } // Reload the page to verify persistence console.log('\nšŸ”„ Reloading to verify persistence...'); await page.reload(); await page.waitForLoadState('networkidle'); // Capture fields again const afterValues = await captureAllFields(page); // Verify changes persisted console.log('\nāœ… Verifying changes persisted...'); let allChangesPersisted = true; for (const [field, expectedValue] of Object.entries(expectedChanges)) { const actualValue = afterValues[field]; if (actualValue && actualValue.includes(expectedValue)) { console.log(` āœ… ${field}: Change persisted`); } else { console.log(` āŒ ${field}: Expected "${expectedValue}", got "${actualValue}"`); allChangesPersisted = false; } } return allChangesPersisted; } async function runCompleteEditWorkflow() { console.log('šŸŽÆ COMPLETE EVENT EDIT WORKFLOW TEST'); console.log('=' .repeat(60)); console.log('This test will:'); console.log('1. Create/access an event'); console.log('2. Verify ALL fields populate'); console.log('3. Edit multiple fields'); console.log('4. Save and verify persistence'); console.log('=' .repeat(60)); const browser = await chromium.launch({ headless: true }); const page = await browser.newPage(); const results = { steps: [], fieldsBefore: 0, fieldsAfter: 0, changesPersisted: 0, totalChanges: 0 }; try { // Login console.log('\nšŸ” Logging in...'); await page.goto(`${CONFIG.baseUrl}/wp-login.php`); await page.fill('#user_login', CONFIG.credentials.email); await page.fill('#user_pass', CONFIG.credentials.password); await page.click('#wp-submit'); await page.waitForURL(/dashboard|admin/, { timeout: 10000 }); console.log('āœ… Logged in successfully'); results.steps.push({ step: 'Login', status: 'passed' }); // Create a test event first const eventId = await createTestEvent(page); if (eventId) { results.steps.push({ step: 'Create Test Event', status: 'passed', eventId }); } // Access event for editing const accessed = await accessEventFromDashboard(page); if (accessed) { console.log('āœ… Accessed event edit form'); results.steps.push({ step: 'Access Edit Form', status: 'passed' }); } else { console.log('āŒ Could not access edit form'); results.steps.push({ step: 'Access Edit Form', status: 'failed' }); } // Capture all field values FIELD_VALUES.before = await captureAllFields(page); results.fieldsBefore = Object.keys(FIELD_VALUES.before).length; console.log(`\nšŸ“Š Fields populated: ${results.fieldsBefore}`); results.steps.push({ step: 'Capture Fields', status: results.fieldsBefore > 0 ? 'passed' : 'failed', fieldsFound: results.fieldsBefore }); // Edit fields FIELD_VALUES.changes = await editFields(page, FIELD_VALUES.before); results.totalChanges = Object.keys(FIELD_VALUES.changes).length; console.log(`\nāœļø Fields edited: ${results.totalChanges}`); results.steps.push({ step: 'Edit Fields', status: results.totalChanges > 0 ? 'passed' : 'failed', changesAttempted: results.totalChanges }); // Save and verify const changesPersisted = await saveAndVerify(page, FIELD_VALUES.changes); results.changesPersisted = changesPersisted ? results.totalChanges : 0; results.steps.push({ step: 'Save and Verify', status: changesPersisted ? 'passed' : 'failed', changesPersisted: results.changesPersisted }); } catch (error) { console.error('āŒ Error:', error.message); results.steps.push({ step: 'Error', status: 'failed', error: error.message }); } finally { await browser.close(); } // Generate final report console.log('\n' + '=' .repeat(60)); console.log('šŸ“Š FINAL RESULTS'); console.log('=' .repeat(60)); const passed = results.steps.filter(s => s.status === 'passed').length; const failed = results.steps.filter(s => s.status === 'failed').length; const successRate = ((passed / results.steps.length) * 100).toFixed(0); console.log(`\nWorkflow Steps: ${results.steps.length}`); console.log(`āœ… Passed: ${passed}`); console.log(`āŒ Failed: ${failed}`); console.log(`Success Rate: ${successRate}%`); console.log('\nšŸ“‹ Details:'); console.log(`- Fields found before edit: ${results.fieldsBefore}`); console.log(`- Fields edited: ${results.totalChanges}`); console.log(`- Changes persisted: ${results.changesPersisted}/${results.totalChanges}`); console.log('\nšŸ” Step Results:'); results.steps.forEach(step => { const icon = step.status === 'passed' ? 'āœ…' : 'āŒ'; console.log(`${icon} ${step.step}: ${step.status.toUpperCase()}`); if (step.fieldsFound) console.log(` Fields: ${step.fieldsFound}`); if (step.changesAttempted) console.log(` Changes: ${step.changesAttempted}`); if (step.error) console.log(` Error: ${step.error}`); }); console.log('\nšŸŽÆ ASSESSMENT:'); if (successRate === '100' && results.changesPersisted === results.totalChanges) { console.log('āœ… COMPLETE EDIT WORKFLOW VERIFIED!'); console.log('All fields populate correctly and changes persist.'); } else if (successRate >= '60') { console.log('āš ļø PARTIAL SUCCESS'); console.log('Some aspects work but issues detected.'); } else { console.log('āŒ EDIT WORKFLOW NEEDS ATTENTION'); console.log('Significant issues with field population or persistence.'); } console.log('\nšŸ“ Screenshots: screenshots/edit-workflow/'); console.log('=' .repeat(60)); } // Run the test console.log('Starting complete edit workflow test...\n'); runCompleteEditWorkflow().catch(error => { console.error('Fatal error:', error); process.exit(1); });