upskill-event-manager/test-tec-v5-validated.js
Ben 25d5c9ac7d feat: implement TEC v5.0.8 field mapping and best practices
- Created comprehensive field mapping documentation for TEC v5.0.8
- Documented all meta keys, input selectors, and field types
- Built validation tests using correct TEC v5.0.8 selectors
- Verified working selectors through staging environment testing
- Added best practices guide with implementation patterns
- Included JavaScript and PHP code examples
- Documented common issues and solutions
- Added debugging tips and performance optimizations

Test results show successful field discovery and persistence:
- Title, Start Date, End Date, and URL fields verified working
- Cost field may be hidden when Events Tickets is active
- All date/time fields use expected selectors
- Venue and organizer fields use array notation in names

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-18 13:29:20 -03:00

562 lines
No EOL
19 KiB
JavaScript
Executable file
Raw 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
/**
* TEC v5.0.8 VALIDATED FIELD TEST
* Uses the correct field selectors from our field mapping documentation
* Tests complete event edit workflow with proper TEC v5.0.8 selectors
*/
const { chromium } = require('@playwright/test');
const fs = require('fs').promises;
const { execSync } = require('child_process');
// Configure XWayland display
process.env.DISPLAY = ':0';
try {
const xauthFile = execSync('ls /run/user/1000/.mutter-Xwaylandauth.* 2>/dev/null | head -n1', { encoding: 'utf8' }).trim();
if (xauthFile) {
process.env.XAUTHORITY = xauthFile;
}
} catch (e) {
// Continue without XAUTHORITY
}
const CONFIG = {
baseUrl: process.env.UPSKILL_STAGING_URL || 'https://upskill-staging.measurequick.com',
credentials: {
username: 'test_admin',
password: 'TestAdmin2025!'
}
};
/**
* TEC v5.0.8 FIELD MAPPING
* Based on our documented field mapping (docs/TEC-V5-FIELD-MAPPING.md)
*/
const TEC_FIELDS = {
// Core Event Fields
basic: {
'Event Title': {
selector: '#title',
metaKey: 'post_title',
type: 'text'
},
'Event Content': {
selector: '#content',
metaKey: 'post_content',
type: 'wysiwyg'
},
'Event Excerpt': {
selector: '#excerpt',
metaKey: 'post_excerpt',
type: 'textarea'
}
},
// Date & Time Fields
datetime: {
'Start Date': {
selector: '#EventStartDate',
metaKey: '_EventStartDate',
type: 'date',
format: 'YYYY-MM-DD'
},
'End Date': {
selector: '#EventEndDate',
metaKey: '_EventEndDate',
type: 'date',
format: 'YYYY-MM-DD'
},
'Start Time': {
selector: '#EventStartTime',
metaKey: null, // Combined with date
type: 'time',
format: 'HH:MM am/pm'
},
'End Time': {
selector: '#EventEndTime',
metaKey: null, // Combined with date
type: 'time',
format: 'HH:MM am/pm'
},
'All Day Event': {
selector: '#EventAllDay',
metaKey: '_EventAllDay',
type: 'checkbox'
},
'Timezone': {
selector: 'select[name="EventTimezone"]',
metaKey: '_EventTimezone',
type: 'select'
}
},
// Cost & Currency Fields
cost: {
'Event Cost': {
selector: '#EventCost',
metaKey: '_EventCost',
type: 'text'
},
'Currency Symbol': {
selector: '#EventCurrencySymbol',
metaKey: '_EventCurrencySymbol',
type: 'text',
default: '$'
},
'Currency Code': {
selector: '#EventCurrencyCode',
metaKey: '_EventCurrencyCode',
type: 'text',
default: 'USD'
},
'Currency Position': {
selector: 'select[name="EventCurrencyPosition"]',
metaKey: null,
type: 'select'
}
},
// Event Details
details: {
'Event URL': {
selector: '#EventURL',
metaKey: '_EventURL',
type: 'url'
},
'Show Map': {
selector: '#EventShowMap',
metaKey: '_EventShowMap',
type: 'checkbox'
},
'Show Map Link': {
selector: '#EventShowMapLink',
metaKey: '_EventShowMapLink',
type: 'checkbox'
}
},
// Venue Fields
venue: {
'Venue ID': {
selector: 'select[name="venue[VenueID]"]',
metaKey: '_EventVenueID',
type: 'select'
},
'Venue Name': {
selector: 'input[name="venue[Venue]"]',
metaKey: '_VenueVenue',
type: 'text'
},
'Venue Address': {
selector: 'input[name="venue[Address]"]',
metaKey: '_VenueAddress',
type: 'text'
},
'Venue City': {
selector: 'input[name="venue[City]"]',
metaKey: '_VenueCity',
type: 'text'
},
'Venue State': {
selector: 'input[name="venue[State]"]',
metaKey: '_VenueStateProvince',
type: 'text'
},
'Venue Zip': {
selector: 'input[name="venue[Zip]"]',
metaKey: '_VenueZip',
type: 'text'
},
'Venue Country': {
selector: 'select[name="venue[Country]"]',
metaKey: '_VenueCountry',
type: 'select'
},
'Venue Phone': {
selector: 'input[name="venue[Phone]"]',
metaKey: '_VenuePhone',
type: 'tel'
},
'Venue Website': {
selector: 'input[name="venue[URL]"]',
metaKey: '_VenueURL',
type: 'url'
}
},
// Organizer Fields
organizer: {
'Organizer ID': {
selector: 'select[name="organizer[OrganizerID]"]',
metaKey: '_EventOrganizerID',
type: 'select'
},
'Organizer Name': {
selector: 'input[name="organizer[Organizer]"]',
metaKey: '_OrganizerOrganizer',
type: 'text'
},
'Organizer Email': {
selector: 'input[name="organizer[Email]"]',
metaKey: '_OrganizerEmail',
type: 'email'
},
'Organizer Phone': {
selector: 'input[name="organizer[Phone]"]',
metaKey: '_OrganizerPhone',
type: 'tel'
},
'Organizer Website': {
selector: 'input[name="organizer[Website]"]',
metaKey: '_OrganizerWebsite',
type: 'url'
}
}
};
async function screenshot(page, name) {
await fs.mkdir('screenshots/tec-v5-validated', { recursive: true });
const path = `screenshots/tec-v5-validated/${name}-${Date.now()}.png`;
await page.screenshot({ path, fullPage: true });
console.log(`📸 Screenshot: ${name}`);
return path;
}
async function getFieldValue(page, fieldDef) {
try {
const element = await page.$(fieldDef.selector);
if (!element) return null;
switch (fieldDef.type) {
case 'checkbox':
return await element.isChecked();
case 'select':
return await element.inputValue();
case 'wysiwyg':
case 'textarea':
// Try to get from the actual textarea or content div
const textValue = await element.inputValue().catch(() => null);
if (textValue) return textValue;
return await element.textContent();
default:
return await element.inputValue();
}
} catch (e) {
return null;
}
}
async function setFieldValue(page, fieldDef, value) {
try {
const element = await page.$(fieldDef.selector);
if (!element) return false;
switch (fieldDef.type) {
case 'checkbox':
if (value) {
await element.check();
} else {
await element.uncheck();
}
return true;
case 'select':
await element.selectOption(value);
return true;
case 'wysiwyg':
case 'textarea':
case 'text':
case 'date':
case 'time':
case 'url':
case 'email':
case 'tel':
default:
await element.fill(value.toString());
return true;
}
} catch (e) {
console.log(` Error setting field: ${e.message}`);
return false;
}
}
async function runTECv5ValidatedTest() {
console.log('🎯 TEC v5.0.8 VALIDATED FIELD TEST');
console.log('=' .repeat(70));
console.log('Using correct field selectors from TEC v5.0.8 documentation');
console.log('=' .repeat(70));
const browser = await chromium.launch({
headless: false,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
const results = {
loginSuccess: false,
eventsFound: 0,
fieldsFound: {},
fieldsPopulated: {},
fieldsTested: 0,
fieldsWorking: 0,
editTestResults: {}
};
try {
// 1. LOGIN
console.log('\n📝 STEP 1: Login');
console.log('-' .repeat(50));
await page.goto(`${CONFIG.baseUrl}/training-login`);
await page.waitForLoadState('networkidle');
// Use the training login form selectors
await page.fill('input[name="log"]', CONFIG.credentials.username);
await page.fill('input[name="pwd"]', CONFIG.credentials.password);
await page.click('input[type="submit"]');
// Wait for redirect to dashboard
await page.waitForURL('**/dashboard/**', { timeout: 15000 });
results.loginSuccess = true;
console.log('✅ Logged in successfully');
// 2. ACCESS EVENT EDIT FORM
console.log('\n📝 STEP 2: Opening Event Edit Form');
console.log('-' .repeat(50));
// From dashboard, go to manage events page
await page.goto(`${CONFIG.baseUrl}/trainer/event/manage/`);
await page.waitForLoadState('networkidle');
await screenshot(page, 'manage-events-page');
// Look for event list on the manage page
const eventLinks = await page.$$('.hvac-events-list a[href*="edit"], .event-actions a:has-text("Edit")');
results.eventsFound = eventLinks.length;
console.log(`✅ Found ${results.eventsFound} events on manage page`);
if (results.eventsFound === 0) {
// Try alternate approach - go directly to wp-admin
console.log('⚠️ No events on manage page, trying wp-admin...');
await page.goto(`${CONFIG.baseUrl}/wp-admin/edit.php?post_type=tribe_events`);
await page.waitForLoadState('networkidle');
const eventRows = await page.$$('tbody#the-list tr');
results.eventsFound = eventRows.length;
console.log(` Found ${results.eventsFound} events in wp-admin`);
if (results.eventsFound === 0) {
console.log('❌ No events found - running seed script...');
execSync('bash bin/create-test-admin-and-seed.sh', { stdio: 'inherit' });
await page.reload();
await page.waitForLoadState('networkidle');
}
// Click edit on first event from wp-admin
const editLink = await page.$('tbody#the-list tr:first-child .row-actions .edit a');
if (editLink) {
await editLink.click();
}
} else {
// Click first edit link from manage page
await eventLinks[0].click();
}
await page.waitForLoadState('networkidle');
console.log('✅ Edit form opened');
await screenshot(page, 'edit-form');
// 3. TEST FIELD DISCOVERY WITH CORRECT SELECTORS
console.log('\n📝 STEP 3: Testing TEC v5.0.8 Field Selectors');
console.log('-' .repeat(50));
for (const [category, fields] of Object.entries(TEC_FIELDS)) {
console.log(`\n🔍 Testing ${category.toUpperCase()} fields:`);
for (const [fieldName, fieldDef] of Object.entries(fields)) {
results.fieldsTested++;
const element = await page.$(fieldDef.selector);
if (element) {
const isVisible = await element.isVisible().catch(() => false);
const value = await getFieldValue(page, fieldDef);
results.fieldsFound[fieldName] = {
found: true,
visible: isVisible,
value: value,
selector: fieldDef.selector,
metaKey: fieldDef.metaKey
};
if (isVisible) {
results.fieldsWorking++;
if (value !== null && value !== '' && value !== false) {
results.fieldsPopulated[fieldName] = value;
console.log(`${fieldName}: POPULATED - "${String(value).substring(0, 50)}"`);
} else {
console.log(`${fieldName}: FOUND (empty)`);
}
} else {
console.log(` ⚠️ ${fieldName}: Hidden`);
}
} else {
results.fieldsFound[fieldName] = {
found: false,
selector: fieldDef.selector
};
console.log(`${fieldName}: NOT FOUND`);
}
}
}
// 4. EDIT TEST WITH CORRECT SELECTORS
console.log('\n📝 STEP 4: Testing Field Updates');
console.log('-' .repeat(50));
const testEdits = {
'Event Title': 'TEC v5.0.8 Test Event - EDITED',
'Start Date': '2025-12-25',
'End Date': '2025-12-26',
'Event Cost': '999',
'Event URL': 'https://tec-v5-test.example.com'
};
for (const [fieldName, newValue] of Object.entries(testEdits)) {
// Find the field definition
let fieldDef = null;
for (const category of Object.values(TEC_FIELDS)) {
if (category[fieldName]) {
fieldDef = category[fieldName];
break;
}
}
if (fieldDef) {
const success = await setFieldValue(page, fieldDef, newValue);
if (success) {
console.log(`${fieldName} updated to: ${newValue}`);
results.editTestResults[fieldName] = 'updated';
} else {
console.log(`${fieldName} update failed`);
results.editTestResults[fieldName] = 'failed';
}
}
}
await screenshot(page, 'after-edits');
// 5. SAVE AND VERIFY
console.log('\n📝 STEP 5: Saving and Verifying');
console.log('-' .repeat(50));
const publishButton = await page.$('#publish');
if (publishButton) {
await publishButton.click();
console.log(' Saving changes...');
try {
await page.waitForSelector('.notice-success, #message', { timeout: 10000 });
console.log('✅ Changes saved');
} catch (e) {
console.log('⚠️ Save confirmation not detected');
}
// Reload and verify
await page.reload();
await page.waitForLoadState('networkidle');
console.log('\n Verifying persistence:');
for (const [fieldName, expectedValue] of Object.entries(testEdits)) {
let fieldDef = null;
for (const category of Object.values(TEC_FIELDS)) {
if (category[fieldName]) {
fieldDef = category[fieldName];
break;
}
}
if (fieldDef) {
const currentValue = await getFieldValue(page, fieldDef);
if (currentValue === expectedValue ||
(currentValue && currentValue.includes && currentValue.includes(expectedValue))) {
console.log(`${fieldName}: PERSISTED`);
results.editTestResults[fieldName] = 'persisted';
} else {
console.log(`${fieldName}: NOT persisted (current: ${currentValue})`);
results.editTestResults[fieldName] = 'not_persisted';
}
}
}
}
} catch (error) {
console.error('\n❌ Error:', error.message);
await screenshot(page, 'error');
} finally {
console.log('\n⏱ Keeping browser open for 5 seconds...');
await page.waitForTimeout(5000);
await browser.close();
}
return results;
}
// Run the test
console.log('Starting TEC v5.0.8 validated field test...\n');
runTECv5ValidatedTest().then(results => {
console.log('\n' + '=' .repeat(70));
console.log('📊 TEC v5.0.8 VALIDATION REPORT');
console.log('=' .repeat(70));
console.log('\n✅ Field Discovery Results:');
console.log(` • Total fields tested: ${results.fieldsTested}`);
console.log(` • Fields found & visible: ${results.fieldsWorking}`);
console.log(` • Fields populated: ${Object.keys(results.fieldsPopulated).length}`);
console.log('\n✅ Working Field Selectors:');
for (const [field, data] of Object.entries(results.fieldsFound)) {
if (data.found && data.visible) {
console.log(`${field}: ${data.selector}`);
}
}
console.log('\n⚠ Missing or Hidden Fields:');
for (const [field, data] of Object.entries(results.fieldsFound)) {
if (!data.found || !data.visible) {
console.log(`${field}: ${data.found ? 'Hidden' : 'Not Found'} (${data.selector})`);
}
}
console.log('\n✅ Edit Test Results:');
const persistedCount = Object.values(results.editTestResults)
.filter(r => r === 'persisted').length;
console.log(` • Changes persisted: ${persistedCount}/${Object.keys(results.editTestResults).length}`);
for (const [field, result] of Object.entries(results.editTestResults)) {
const icon = result === 'persisted' ? '✅' : '❌';
console.log(` ${icon} ${field}: ${result}`);
}
console.log('\n' + '=' .repeat(70));
console.log('📌 SUMMARY');
console.log('-' .repeat(70));
if (results.fieldsWorking >= 20 && persistedCount >= 3) {
console.log('\n✅✅✅ TEC v5.0.8 VALIDATION SUCCESSFUL! ✅✅✅');
console.log('Field selectors are correct and working!');
console.log('Event editing with TEC v5.0.8 is fully functional!');
} else {
console.log('\n⚠ PARTIAL SUCCESS');
console.log('Some field selectors may need adjustment.');
console.log('Review the missing/hidden fields above.');
}
console.log('\n📁 Screenshots saved to: screenshots/tec-v5-validated/');
console.log('📄 Field mapping documented in: docs/TEC-V5-FIELD-MAPPING.md');
console.log('=' .repeat(70));
}).catch(error => {
console.error('Fatal error:', error);
process.exit(1);
});