upskill-event-manager/test-complete-edit-workflow.js
Ben 023d77541c feat: Add event seeding functionality and comprehensive edit workflow tests
- 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>
2025-08-18 10:40:11 -03:00

514 lines
No EOL
18 KiB
JavaScript
Executable file
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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);
});