upskill-event-manager/wordpress-dev/tests/e2e/trainer-journey-complete.test.ts
bengizmo 057b0e8212 test: Update E2E tests for TEC Community Events form
- Update debug-event-creation.test.ts with comprehensive TEC form detection
- Create event-creation-tec.test.ts for TEC-specific event workflows
- Add trainer-journey-complete.test.ts for full trainer workflow testing
- Add tec-shortcode-check.test.ts to verify shortcode processing
- Create event-creation-integration.test.ts for end-to-end integration
- Update all tests to use TEC form selectors and handle editor types
- Add proper error handling for when TEC shortcode shows as raw text

These tests support the fix that removed the HVAC shortcode override,
allowing The Events Calendar Community Events to handle the form properly.

Co-Authored-By: Ben Reed <ben@tealmaker.com>
2025-05-30 09:53:41 -06:00

472 lines
No EOL
15 KiB
TypeScript

import { test, expect } from './fixtures/auth';
import { CommonActions } from './utils/common-actions';
/**
* Complete Trainer Journey Test Suite
*
* Tests the full workflow of a trainer:
* 1. Login and dashboard access
* 2. Create a new event using TEC Community Events
* 3. View event in dashboard
* 4. Edit the event
* 5. Generate certificates (if attendees exist)
* 6. View trainer profile
*/
test.describe('Complete Trainer Journey', () => {
let eventTitle: string;
let eventId: string;
test.beforeEach(async ({ authenticatedPage: page }) => {
const actions = new CommonActions(page);
// Verify we're logged in and on dashboard
await expect(page).toHaveURL(/hvac-dashboard/);
await actions.screenshot('journey-start-dashboard');
});
test('1. Dashboard Overview', async ({ authenticatedPage: page }) => {
test.setTimeout(30000);
const actions = new CommonActions(page);
// Check dashboard elements
await expect(page.locator('h1:has-text("Trainer Dashboard")')).toBeVisible();
// Verify navigation elements
const navElements = {
createEvent: page.locator('a:has-text("Create Event")').first(),
myEvents: page.locator('a:has-text("My Events")').first(),
certificateReports: page.locator('a:has-text("Certificate Reports")').first(),
generateCertificates: page.locator('a:has-text("Generate Certificates")').first(),
profile: page.locator('a:has-text("View Profile")').first()
};
for (const [name, element] of Object.entries(navElements)) {
await expect(element).toBeVisible({ timeout: 5000 });
console.log(`${name} link is visible`);
}
// Check statistics
const stats = await page.locator('.hvac-stat-card').count();
console.log(`Dashboard shows ${stats} statistics cards`);
// Check events table
const eventsTable = page.locator('.hvac-events-table, table').first();
await expect(eventsTable).toBeVisible();
await actions.screenshot('journey-dashboard-verified');
});
test('2. Create New Event', async ({ authenticatedPage: page }) => {
test.setTimeout(90000);
const actions = new CommonActions(page);
// Navigate to Create Event
await page.click('a:has-text("Create Event")');
await page.waitForLoadState('networkidle');
await actions.screenshot('journey-create-event-page');
// Generate unique event data
const testData = actions.generateTestData('Training');
eventTitle = `${testData.title} - Trainer Journey Test`;
const eventDetails = {
title: eventTitle,
description: `${testData.description}
This comprehensive HVAC training covers:
- System diagnostics and troubleshooting
- Energy efficiency optimization
- Latest industry standards and regulations
- Hands-on practical exercises
Prerequisites: Basic HVAC knowledge
Duration: Full day workshop
Certification: Completion certificate provided`,
venue: 'HVAC Excellence Training Center',
address: '456 Training Blvd, Suite 100',
city: 'Dallas',
state: 'TX',
zip: '75201'
};
// Wait for form to be ready
await page.waitForTimeout(2000);
// Try different form selectors based on what TEC might use
const titleSelectors = [
'input[name="post_title"]',
'input#post_title',
'input[name="event_title"]',
'#event_title',
'input[placeholder*="Event Title"]'
];
let titleFilled = false;
for (const selector of titleSelectors) {
const field = page.locator(selector).first();
if (await field.count() > 0 && await field.isVisible()) {
await field.fill(eventDetails.title);
titleFilled = true;
console.log(`✓ Filled title using selector: ${selector}`);
break;
}
}
if (!titleFilled) {
throw new Error('Could not find event title field');
}
// Fill description - try different approaches
const contentFilled = await fillEventDescription(page, eventDetails.description);
if (!contentFilled) {
console.log('Warning: Could not fill event description');
}
// Set event dates (1 week from now)
const eventDate = new Date();
eventDate.setDate(eventDate.getDate() + 7);
const dateStr = eventDate.toISOString().split('T')[0];
const dateSelectors = [
{ field: 'EventStartDate', value: dateStr },
{ field: 'EventEndDate', value: dateStr },
{ field: 'event_start_date', value: dateStr },
{ field: 'event_end_date', value: dateStr }
];
for (const { field, value } of dateSelectors) {
const input = page.locator(`input[name="${field}"], input#${field}`).first();
if (await input.count() > 0 && await input.isVisible()) {
await input.fill(value);
console.log(`✓ Filled ${field}`);
}
}
// Set times if separate fields exist
const timeFields = [
{ field: 'EventStartTime', value: '09:00' },
{ field: 'EventEndTime', value: '17:00' },
{ field: 'event_start_time', value: '09:00 AM' },
{ field: 'event_end_time', value: '05:00 PM' }
];
for (const { field, value } of timeFields) {
const input = page.locator(`input[name="${field}"], input#${field}`).first();
if (await input.count() > 0 && await input.isVisible()) {
await input.fill(value);
}
}
// Fill venue information
const venueFields = [
{ field: 'venue[Venue]', value: eventDetails.venue },
{ field: 'venue[Address]', value: eventDetails.address },
{ field: 'venue[City]', value: eventDetails.city },
{ field: 'venue[State]', value: eventDetails.state },
{ field: 'venue[Zip]', value: eventDetails.zip }
];
for (const { field, value } of venueFields) {
const input = page.locator(`input[name="${field}"], input#venue-${field.toLowerCase()}`).first();
if (await input.count() > 0 && await input.isVisible()) {
await input.fill(value);
console.log(`✓ Filled venue ${field}`);
}
}
await actions.screenshot('journey-event-form-filled');
// Find and click submit button
const submitSelectors = [
'input[type="submit"][value*="Submit"]',
'button[type="submit"]',
'input[type="submit"].button-primary',
'#submitButton',
'.tribe-submit-button'
];
let submitted = false;
for (const selector of submitSelectors) {
const button = page.locator(selector).first();
if (await button.count() > 0 && await button.isVisible()) {
await Promise.all([
page.waitForNavigation({ timeout: 30000, waitUntil: 'networkidle' }).catch(() => {}),
button.click()
]);
submitted = true;
console.log(`✓ Clicked submit using selector: ${selector}`);
break;
}
}
if (!submitted) {
throw new Error('Could not find submit button');
}
await actions.screenshot('journey-after-event-submit');
// Check for success
const successSelectors = [
'.tribe-success',
'.notice-success',
'.updated',
'text=successfully',
'text=pending review'
];
let successFound = false;
for (const selector of successSelectors) {
const element = page.locator(selector).first();
if (await element.count() > 0) {
successFound = true;
console.log(`✓ Success indicator found: ${selector}`);
console.log(`Message: ${await element.textContent()}`);
break;
}
}
expect(successFound).toBe(true);
});
test('3. Verify Event in Dashboard', async ({ authenticatedPage: page }) => {
test.setTimeout(30000);
const actions = new CommonActions(page);
// Navigate to dashboard
await actions.navigateAndWait('/hvac-dashboard/');
// Look for our event
const eventRow = page.locator(`tr:has-text("${eventTitle}")`).first();
const eventFound = await eventRow.count() > 0;
if (eventFound) {
console.log('✓ Event found in dashboard!');
// Get event details
const status = await eventRow.locator('td').first().textContent();
console.log(`Event status: ${status}`);
// Find edit link to get event ID
const editLink = eventRow.locator('a:has-text("Edit")').first();
if (await editLink.count() > 0) {
const href = await editLink.getAttribute('href');
const match = href?.match(/event_id=(\d+)/);
if (match) {
eventId = match[1];
console.log(`Event ID: ${eventId}`);
}
}
await actions.screenshot('journey-event-in-dashboard');
} else {
console.log('Event not immediately visible (may be pending approval)');
// Try different filters
const filters = ['pending', 'draft', 'all'];
for (const filter of filters) {
const filterLink = page.locator(`a:has-text("${filter}")`).first();
if (await filterLink.count() > 0) {
await filterLink.click();
await page.waitForTimeout(1000);
const found = await page.locator(`tr:has-text("${eventTitle}")`).count() > 0;
if (found) {
console.log(`✓ Event found under ${filter} filter`);
break;
}
}
}
}
});
test('4. Edit Event', async ({ authenticatedPage: page }) => {
test.setTimeout(60000);
const actions = new CommonActions(page);
// Start from dashboard
await actions.navigateAndWait('/hvac-dashboard/');
// Find our event or any event to edit
let editLink = page.locator(`tr:has-text("${eventTitle}") a:has-text("Edit")`).first();
if (await editLink.count() === 0) {
// If our specific event isn't found, edit any available event
editLink = page.locator('a:has-text("Edit")').first();
}
const hasEditableEvent = await editLink.count() > 0;
if (!hasEditableEvent) {
console.log('No editable events found, skipping edit test');
test.skip();
return;
}
// Click edit
await editLink.click();
await page.waitForLoadState('networkidle');
await actions.screenshot('journey-edit-event-page');
// Update title
const titleField = page.locator('input[name="post_title"], input#post_title').first();
await expect(titleField).toBeVisible();
const currentTitle = await titleField.inputValue();
const updatedTitle = `${currentTitle} (Updated ${new Date().toLocaleTimeString()})`;
await titleField.fill(updatedTitle);
// Add to description
const updateNote = `\n\n[Update ${new Date().toLocaleString()}]: Schedule confirmed, materials updated.`;
const contentUpdated = await fillEventDescription(page, updateNote, true);
await actions.screenshot('journey-edit-form-updated');
// Submit changes
const submitButton = page.locator('input[type="submit"], button[type="submit"]').first();
await expect(submitButton).toBeVisible();
await Promise.all([
page.waitForNavigation({ timeout: 30000 }).catch(() => {}),
submitButton.click()
]);
await actions.screenshot('journey-after-edit-submit');
// Verify update success
const successMessage = page.locator('.tribe-success, .notice-success, .updated').first();
const hasSuccess = await successMessage.count() > 0;
if (hasSuccess) {
console.log('✓ Event updated successfully');
}
});
test('5. View Trainer Profile', async ({ authenticatedPage: page }) => {
test.setTimeout(30000);
const actions = new CommonActions(page);
// Navigate to profile
await page.click('a:has-text("View Profile")');
await page.waitForLoadState('networkidle');
await actions.screenshot('journey-trainer-profile');
// Verify profile elements
await expect(page.locator('h1, h2').filter({ hasText: /profile/i }).first()).toBeVisible();
// Check for trainer information
const profileSections = [
'contact information',
'bio',
'experience',
'certifications'
];
for (const section of profileSections) {
const element = page.locator(`text=/${section}/i`).first();
if (await element.count() > 0) {
console.log(`✓ Profile shows ${section}`);
}
}
// Check for edit profile option
const editProfileLink = page.locator('a:has-text("Edit Profile")').first();
if (await editProfileLink.count() > 0) {
console.log('✓ Edit profile option available');
}
});
test('6. Certificate Management', async ({ authenticatedPage: page }) => {
test.setTimeout(30000);
const actions = new CommonActions(page);
// Navigate to certificate reports
await actions.navigateAndWait('/certificate-reports/');
await actions.screenshot('journey-certificate-reports');
// Check page loaded
await expect(page.locator('h1, h2').filter({ hasText: /certificate/i }).first()).toBeVisible();
// Check for statistics
const stats = await page.locator('.stat-value, .metric-value').count();
console.log(`Certificate reports shows ${stats} statistics`);
// Navigate to generate certificates
await page.click('a:has-text("Generate Certificates")');
await page.waitForLoadState('networkidle');
await actions.screenshot('journey-generate-certificates');
// Check if any events are available for certificate generation
const eventDropdown = page.locator('select[name="event_id"], #event_id').first();
if (await eventDropdown.count() > 0) {
const options = await eventDropdown.locator('option').count();
console.log(`Found ${options - 1} events available for certificate generation`);
if (options > 1) {
// Select first real event (skip the placeholder option)
await eventDropdown.selectOption({ index: 1 });
await page.waitForTimeout(1000);
// Check if attendees loaded
const attendeeCheckboxes = page.locator('input[type="checkbox"][name="attendee_ids[]"]');
const attendeeCount = await attendeeCheckboxes.count();
console.log(`Found ${attendeeCount} attendees for selected event`);
}
}
});
});
/**
* Helper function to fill event description in various editor types
*/
async function fillEventDescription(page: any, content: string, append: boolean = false): Promise<boolean> {
// Try TinyMCE first
const tinyMCEFrames = [
'#tcepostcontent_ifr',
'#content_ifr',
'iframe[id*="content"]'
];
for (const frameSelector of tinyMCEFrames) {
const frame = page.frameLocator(frameSelector).first();
const body = frame.locator('body');
if (await body.count() > 0) {
try {
if (append) {
const current = await body.textContent();
await body.fill(current + content);
} else {
await body.fill(content);
}
console.log('✓ Filled content in TinyMCE editor');
return true;
} catch (e) {
continue;
}
}
}
// Try regular textarea
const textareaSelectors = [
'textarea[name="post_content"]',
'textarea#tcepostcontent',
'textarea[name="event_description"]',
'#event_description'
];
for (const selector of textareaSelectors) {
const textarea = page.locator(selector).first();
if (await textarea.count() > 0 && await textarea.isVisible()) {
if (append) {
const current = await textarea.inputValue();
await textarea.fill(current + content);
} else {
await textarea.fill(content);
}
console.log(`✓ Filled content in textarea: ${selector}`);
return true;
}
}
return false;
}