import { STAGING_URL, PATHS, TIMEOUTS } from './config/staging-config'; import { test, expect, Page } from '@playwright/test'; import * as dotenv from 'dotenv'; import { resolve } from 'path'; dotenv.config({ path: resolve(__dirname, '../../../../.env') }); test.use({ screenshot: 'only-on-failure', video: 'retain-on-failure', trace: 'retain-on-failure', actionTimeout: 30000, timeout: 120000, // 2 minutes per test }); test.describe('Event Creation with Fixed Validation', () => { const stagingUrl = process.env.UPSKILL_STAGING_URL || 'https://upskill-staging.measurequick.com'; test('creates event with proper field naming', async ({ page }) => { const username = 'test_trainer'; const password = 'Test123!'; // Step 1: Clear Breeze cache first console.log('Clearing Breeze cache...'); const { execSync } = require('child_process'); try { execSync('/Users/ben/dev/upskill-event-manager/wordpress-dev/bin/clear-breeze-cache.sh', { stdio: 'inherit', cwd: '/Users/ben/dev/upskill-event-manager/wordpress-dev' }); } catch (error) { console.error('Failed to clear Breeze cache:', error); } // Step 2: Login await page.goto(stagingUrl + '/community-login/', { waitUntil: 'domcontentloaded' }); await page.fill('input#user_login', username); await page.fill('input#user_pass', password); await page.getByRole('button', { name: /log in/i }).click(); // Wait for login to complete await page.waitForURL(/hvac-dashboard|manage-event/, { timeout: 30000 }); // Step 3: Navigate directly to event creation await page.goto(stagingUrl + '/manage-event/', { waitUntil: 'domcontentloaded' }); await page.waitForSelector('input[name="post_title"]', { state: 'visible' }); // Step 4: Fill form fields const now = new Date(); const uniqueTitle = `HVAC Training ${now.toISOString().split('.')[0].replace(/[-T:]/g, '')}`; await page.fill('input[name="post_title"]', uniqueTitle); // Set dates const eventDate = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); const dateStr = eventDate.toISOString().split('T')[0]; await page.fill('input[name="EventStartDate"]', dateStr); await page.fill('input[name="EventEndDate"]', dateStr); await page.fill('input[name="EventStartTime"]', '09:00'); await page.fill('input[name="EventEndTime"]', '17:00'); // Set venue await page.fill('input[name="venue[Venue]"]', 'New Test Venue'); await page.fill('input[name="venue[Address]"]', '789 Test St'); await page.fill('input[name="venue[City]"]', 'Test City'); await page.fill('input[name="venue[Province]"]', 'BC'); await page.fill('input[name="venue[Country]"]', 'Canada'); await page.fill('input[name="venue[Zip]"]', 'V1X 1X1'); // Step 5: Handle description field with proper naming const descriptionText = `This is a test event created on ${now.toISOString()}. This event covers HVAC training basics.`; // Try multiple approaches to ensure the description is set // 1. Fill the textarea directly try { await page.fill('textarea[name="tcepostcontent"]', descriptionText); } catch (e) { console.log('Direct textarea fill failed:', e.message); } // 2. Handle TinyMCE editor if present try { const iframe = page.frameLocator('iframe#tcepostcontent_ifr'); const iframeBody = iframe.locator('body'); await iframeBody.click(); await iframeBody.fill(descriptionText); } catch (e) { console.log('TinyMCE iframe approach failed:', e.message); } // 3. Use JavaScript to set both tcepostcontent and post_content await page.evaluate((content) => { // Set the visible textarea const textarea = document.querySelector('textarea[name="tcepostcontent"]') as HTMLTextAreaElement; if (textarea) { textarea.value = content; textarea.dispatchEvent(new Event('change', { bubbles: true })); } // Create a hidden field for post_content if it doesn't exist let postContentField = document.querySelector('input[name="post_content"], textarea[name="post_content"]') as HTMLInputElement; if (!postContentField) { postContentField = document.createElement('input'); postContentField.type = 'hidden'; postContentField.name = 'post_content'; const form = document.querySelector('form'); if (form) { form.appendChild(postContentField); } } postContentField.value = content; // Also try TinyMCE API if available if ((window as any).tinymce) { const editor = (window as any).tinymce.get('tcepostcontent'); if (editor) { editor.setContent(content); } } }, descriptionText); // Set additional fields await page.selectOption('select[name="EventOrganizerID"]', { index: 1 }); await page.fill('input[name="ticket_price"]', '100'); await page.fill('input[name="ticket_quantity"]', '20'); // Take screenshot before submission await page.screenshot({ path: 'before-submission-fixed.png', fullPage: true }); // Step 6: Submit form with both field names await page.evaluate(() => { // Ensure both field names have the content const tceContent = (document.querySelector('textarea[name="tcepostcontent"]') as HTMLTextAreaElement)?.value; const postContentField = document.querySelector('input[name="post_content"], textarea[name="post_content"]') as HTMLInputElement; if (tceContent && postContentField) { postContentField.value = tceContent; } }); // Submit the form await page.click('input[type="submit"][value="Submit Event"]'); await page.waitForLoadState('networkidle'); // Check for success or error const pageContent = await page.content(); const errorExists = await page.locator('.tribe-notice-error, .error-message').isVisible().catch(() => false); if (errorExists) { await page.screenshot({ path: 'submission-error-fixed.png', fullPage: true }); const errorText = await page.locator('.tribe-notice-error, .error-message').textContent(); console.error('Submission error:', errorText); } // Verify success if (pageContent.includes(uniqueTitle) || pageContent.includes('Event submitted')) { console.log('Event created successfully!'); } else { throw new Error('Event creation may have failed'); } }); });