Fixed critical issues with Generate Certificates page: - Replaced tribe_tickets_get_attendees() with direct database queries - Added support for both TEC and TPP attendee post types - Fixed attendee meta keys to show real names and emails - Added proper CSS styling and navigation buttons - Updated test utilities with correct staging URL Generate Certificates page now fully functional: - Shows 16 events in dropdown - Displays 5 attendees with proper data - Successfully generates certificates with confirmation message - Includes Dashboard and Certificate Reports navigation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
200 lines
No EOL
7.4 KiB
TypeScript
200 lines
No EOL
7.4 KiB
TypeScript
import { Page } from '@playwright/test';
|
|
|
|
/**
|
|
* Utility class for creating test data for certificate tests
|
|
*
|
|
* This class handles:
|
|
* 1. Setting up test events with attendees
|
|
* 2. Checking in some attendees
|
|
* 3. Cleaning up test data after tests
|
|
*/
|
|
export class CertificateTestData {
|
|
private page: Page;
|
|
private readonly baseUrl = 'https://upskill-staging.measurequick.com';
|
|
private readonly loginUrl = '/community-login/';
|
|
private readonly dashboardUrl = '/hvac-dashboard/';
|
|
private readonly adminUrl = '/wp-admin/';
|
|
|
|
private readonly username = 'test_trainer';
|
|
private readonly password = 'Test123!';
|
|
|
|
private testEventId: string | null = null;
|
|
private testEventName: string | null = null;
|
|
|
|
constructor(page: Page) {
|
|
this.page = page;
|
|
}
|
|
|
|
/**
|
|
* Login as a trainer user for test setup
|
|
*/
|
|
async loginAsTrainer(): Promise<void> {
|
|
await this.page.goto(`${this.baseUrl}${this.loginUrl}`);
|
|
await this.page.fill('#user_login', this.username);
|
|
await this.page.fill('#user_pass', this.password);
|
|
await this.page.click('#wp-submit');
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
|
// Verify login was successful
|
|
const url = this.page.url();
|
|
if (!url.includes(this.dashboardUrl)) {
|
|
throw new Error(`Login failed. Expected URL to contain ${this.dashboardUrl}, but got ${url}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set up a test event with attendees for certificate testing
|
|
* @returns The name of the created test event
|
|
*/
|
|
async setupCertificateTestEvent(): Promise<string | null> {
|
|
// Generate a unique event name with timestamp
|
|
const timestamp = new Date().getTime();
|
|
this.testEventName = `Certificate Test Event ${timestamp}`;
|
|
|
|
// Navigate to create event page
|
|
await this.page.goto(`${this.baseUrl}/community-events/`);
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
|
// Populate the event form with test data
|
|
await this.page.fill('#post_title', this.testEventName);
|
|
|
|
// Set event date (today + 1 day)
|
|
const tomorrow = new Date();
|
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
const dateString = tomorrow.toISOString().split('T')[0]; // Format as YYYY-MM-DD
|
|
|
|
// Fill event date fields
|
|
await this.page.fill('input[name="EventStartDate"]', dateString);
|
|
await this.page.fill('input[name="EventEndDate"]', dateString);
|
|
|
|
// Set content using TinyMCE if available
|
|
const tinyMceFrame = this.page.frameLocator('.mce-edit-area iframe');
|
|
if (await tinyMceFrame.count() > 0) {
|
|
await tinyMceFrame.locator('body').fill('This is a test event for certificate generation testing.');
|
|
} else {
|
|
// Fallback to regular textarea
|
|
await this.page.fill('#post_content', 'This is a test event for certificate generation testing.');
|
|
}
|
|
|
|
// Fill other required fields
|
|
await this.page.fill('#EventVenueName', 'Test Venue');
|
|
await this.page.fill('#EventVenueAddress', '123 Test Street');
|
|
await this.page.fill('#EventVenueCity', 'Test City');
|
|
await this.page.fill('#EventVenueCountry', 'United States');
|
|
await this.page.fill('#EventVenueZip', '12345');
|
|
|
|
// Create ticket
|
|
await this.page.click('text=Tickets');
|
|
await this.page.click('text=Add a new ticket');
|
|
await this.page.fill('.tribe-ticket-field-name input', 'General Admission');
|
|
await this.page.fill('.tribe-ticket-field-price input', '10');
|
|
await this.page.fill('.tribe-ticket-field-capacity input', '100');
|
|
|
|
// Save event
|
|
await this.page.click('#community-events-submit');
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
|
// Extract the event ID from the URL or response
|
|
const url = this.page.url();
|
|
const match = url.match(/post=(\d+)/);
|
|
if (match && match[1]) {
|
|
this.testEventId = match[1];
|
|
console.log(`Created test event with ID: ${this.testEventId}`);
|
|
} else {
|
|
console.error('Failed to extract event ID from URL:', url);
|
|
}
|
|
|
|
// Create test attendees via API for efficiency
|
|
await this.createTestAttendees();
|
|
|
|
return this.testEventName;
|
|
}
|
|
|
|
/**
|
|
* Create test attendees for the event
|
|
* Creates 5 attendees: 3 checked-in, 2 not checked-in
|
|
*/
|
|
private async createTestAttendees(): Promise<void> {
|
|
if (!this.testEventId) {
|
|
throw new Error('Cannot create attendees: No test event ID available');
|
|
}
|
|
|
|
// Login to admin to create test attendees
|
|
await this.page.goto(`${this.baseUrl}${this.adminUrl}`);
|
|
await this.page.fill('#user_login', this.username);
|
|
await this.page.fill('#user_pass', this.password);
|
|
await this.page.click('#wp-submit');
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
|
// Create 5 test attendees
|
|
const attendeeData = [
|
|
{ name: 'Test Attendee 1', email: 'test1@example.com', checkedIn: true },
|
|
{ name: 'Test Attendee 2', email: 'test2@example.com', checkedIn: true },
|
|
{ name: 'Test Attendee 3', email: 'test3@example.com', checkedIn: true },
|
|
{ name: 'Test Attendee 4', email: 'test4@example.com', checkedIn: false },
|
|
{ name: 'Test Attendee 5', email: 'test5@example.com', checkedIn: false }
|
|
];
|
|
|
|
// Navigate to Event Tickets > Attendees page
|
|
await this.page.goto(`${this.baseUrl}${this.adminUrl}edit.php?post_type=tribe_events&page=tickets-attendees&event_id=${this.testEventId}`);
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
|
for (const attendee of attendeeData) {
|
|
// Add attendee manually
|
|
await this.page.click('a:text("Add a new attendee")');
|
|
await this.page.waitForSelector('form.tribe-attendees-page-add-attendee-form');
|
|
|
|
// Fill attendee details
|
|
await this.page.selectOption('select[name="ticket_id"]', { index: 0 }); // Select the first ticket
|
|
await this.page.fill('input[name="attendee[full_name]"]', attendee.name);
|
|
await this.page.fill('input[name="attendee[email]"]', attendee.email);
|
|
|
|
// Submit the form
|
|
await this.page.click('button:text("Add")');
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
|
// Check in the attendee if needed
|
|
if (attendee.checkedIn) {
|
|
// Find the attendee row
|
|
const attendeeRow = this.page.locator(`tr:has-text("${attendee.email}")`).first();
|
|
|
|
// Click the check-in button
|
|
await attendeeRow.locator('.check-in').click();
|
|
await this.page.waitForLoadState('networkidle');
|
|
}
|
|
}
|
|
|
|
console.log(`Created ${attendeeData.length} test attendees for event ${this.testEventId}`);
|
|
}
|
|
|
|
/**
|
|
* Clean up test data
|
|
*/
|
|
async cleanup(): Promise<void> {
|
|
if (!this.testEventId) {
|
|
console.log('No test data to clean up');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Login to admin if needed
|
|
if (!this.page.url().includes(this.adminUrl)) {
|
|
await this.page.goto(`${this.baseUrl}${this.adminUrl}`);
|
|
await this.page.fill('#user_login', this.username);
|
|
await this.page.fill('#user_pass', this.password);
|
|
await this.page.click('#wp-submit');
|
|
await this.page.waitForLoadState('networkidle');
|
|
}
|
|
|
|
// Move the event to trash
|
|
await this.page.goto(`${this.baseUrl}${this.adminUrl}post.php?post=${this.testEventId}&action=trash`);
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
|
console.log(`Cleaned up test event with ID: ${this.testEventId}`);
|
|
this.testEventId = null;
|
|
this.testEventName = null;
|
|
} catch (error) {
|
|
console.error('Error during test data cleanup:', error);
|
|
}
|
|
}
|
|
} |