- Created CertificatePage class for testing certificate functionality - Updated DashboardPage to support certificate links in navigation - Implemented test data generator for certificate testing - Added tests for certificate generation with checked-in users - Added tests for certificate generation with non-checked-in users - Added certificate management (view/email/revoke) tests - Created comprehensive trainer journey test including certificates - Added utility script to run certificate-specific tests 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
181 lines
No EOL
7.3 KiB
TypeScript
181 lines
No EOL
7.3 KiB
TypeScript
import { Page } from '@playwright/test';
|
|
import { VerbosityController } from './VerbosityController';
|
|
|
|
/**
|
|
* Utility class to set up test data for certificate testing
|
|
* This helps ensure we have events with both checked-in and non-checked-in attendees
|
|
*/
|
|
export class CertificateTestData {
|
|
private page: Page;
|
|
private verbosity: VerbosityController;
|
|
private readonly STAGING_URL = 'https://wordpress-974670-5399585.cloudwaysapps.com';
|
|
|
|
constructor(page: Page) {
|
|
this.page = page;
|
|
this.verbosity = VerbosityController.getInstance();
|
|
}
|
|
|
|
/**
|
|
* Login as the test trainer
|
|
*/
|
|
async loginAsTrainer(): Promise<void> {
|
|
this.verbosity.log('Logging in as test_trainer');
|
|
await this.page.goto(`${this.STAGING_URL}/community-login/`);
|
|
await this.page.fill('#user_login', 'test_trainer');
|
|
await this.page.fill('#user_pass', 'Test123!');
|
|
await this.page.click('#wp-submit');
|
|
await this.page.waitForLoadState('networkidle');
|
|
}
|
|
|
|
/**
|
|
* Creates a test event with a specified name and future date
|
|
*/
|
|
async createTestEvent(eventName: string): Promise<string | null> {
|
|
this.verbosity.log(`Creating test event: ${eventName}`);
|
|
|
|
await this.page.goto(`${this.STAGING_URL}/manage-event/`);
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
|
// Fill in event details
|
|
await this.page.fill('#post_title, input[name="post_title"]', eventName);
|
|
|
|
// Add description
|
|
const newEventFrame = this.page.frameLocator('iframe[id*="_ifr"]');
|
|
const newEventBody = newEventFrame.locator('body');
|
|
await newEventBody.fill(`This is a test event created for certificate testing: ${eventName}`);
|
|
|
|
// Set dates (30 days from now)
|
|
const futureDate = new Date();
|
|
futureDate.setDate(futureDate.getDate() + 30);
|
|
const dateString = `${(futureDate.getMonth() + 1).toString().padStart(2, '0')}/${futureDate.getDate().toString().padStart(2, '0')}/${futureDate.getFullYear()}`;
|
|
|
|
await this.page.fill('input[name="EventStartDate"]', dateString);
|
|
await this.page.fill('input[name="EventStartTime"]', '10:00 AM');
|
|
await this.page.fill('input[name="EventEndDate"]', dateString);
|
|
await this.page.fill('input[name="EventEndTime"]', '04:00 PM');
|
|
|
|
// Add a ticket for $100
|
|
await this.addTicket('Certificate Test Ticket', '100');
|
|
|
|
// Submit the event
|
|
const submitButton = this.page.locator('input[value="Submit Event"], button:has-text("Submit Event")');
|
|
await submitButton.click();
|
|
await this.page.waitForLoadState('networkidle');
|
|
|
|
// Get the event ID from the URL if possible
|
|
const url = this.page.url();
|
|
const match = url.match(/post=(\d+)/);
|
|
if (match && match[1]) {
|
|
return match[1];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Adds a ticket to an event
|
|
*/
|
|
private async addTicket(ticketName: string, price: string): Promise<void> {
|
|
// Look for ticket creation UI elements
|
|
const ticketNameField = this.page.locator('#tribe-tickets-editor-tickets-name');
|
|
const ticketPriceField = this.page.locator('#tribe-tickets-editor-tickets-price');
|
|
const addTicketButton = this.page.locator('button:has-text("Add Ticket")');
|
|
|
|
// If the ticket UI isn't visible, try to open it
|
|
if (!await ticketNameField.isVisible()) {
|
|
const addTicketsSection = this.page.locator('a:has-text("Add Tickets")');
|
|
if (await addTicketsSection.isVisible()) {
|
|
await addTicketsSection.click();
|
|
await this.page.waitForTimeout(1000);
|
|
}
|
|
}
|
|
|
|
// Fill in ticket details
|
|
if (await ticketNameField.isVisible()) {
|
|
await ticketNameField.fill(ticketName);
|
|
await ticketPriceField.fill(price);
|
|
await addTicketButton.click();
|
|
await this.page.waitForTimeout(2000);
|
|
} else {
|
|
this.verbosity.log('Warning: Ticket creation UI not found');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Simulates attendee registrations for an event
|
|
* Creates a mix of checked-in and non-checked-in attendees
|
|
*/
|
|
async createTestAttendees(eventId: string, count: number = 5): Promise<void> {
|
|
this.verbosity.log(`Creating ${count} test attendees for event ${eventId}`);
|
|
|
|
// First, navigate to the admin area to access the event
|
|
await this.page.goto(`${this.STAGING_URL}/wp-admin/post.php?post=${eventId}&action=edit`);
|
|
|
|
// Check if we're on the login page and log in if needed
|
|
if (this.page.url().includes('wp-login.php')) {
|
|
await this.page.fill('#user_login', 'test_trainer');
|
|
await this.page.fill('#user_pass', 'Test123!');
|
|
await this.page.click('#wp-submit');
|
|
await this.page.waitForLoadState('networkidle');
|
|
}
|
|
|
|
// Navigate to the attendees tab - this is implementation-specific and may need adjustment
|
|
const attendeesTab = this.page.locator('a:has-text("Attendees")');
|
|
if (await attendeesTab.isVisible()) {
|
|
await attendeesTab.click();
|
|
await this.page.waitForTimeout(1000);
|
|
}
|
|
|
|
// Look for "Add New" button
|
|
const addNewButton = this.page.locator('a:has-text("Add attendee"), button:has-text("Add attendee")');
|
|
|
|
for (let i = 1; i <= count; i++) {
|
|
// Click "Add New" for each attendee
|
|
if (await addNewButton.isVisible()) {
|
|
await addNewButton.click();
|
|
await this.page.waitForTimeout(500);
|
|
|
|
// Fill in attendee info
|
|
await this.page.fill('input[name="attendee[email]"]', `test.attendee${i}@example.com`);
|
|
await this.page.fill('input[name="attendee[full_name]"]', `Test Attendee ${i}`);
|
|
|
|
// Mark every other attendee as checked in
|
|
if (i % 2 === 0) {
|
|
const checkinCheckbox = this.page.locator('input[name="attendee[check_in]"]');
|
|
if (await checkinCheckbox.isVisible()) {
|
|
await checkinCheckbox.check();
|
|
}
|
|
}
|
|
|
|
// Save the attendee
|
|
const saveButton = this.page.locator('button:has-text("Add")');
|
|
await saveButton.click();
|
|
await this.page.waitForTimeout(1000);
|
|
} else {
|
|
this.verbosity.log('Warning: Add attendee button not found');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a complete test event with attendees for certificate testing
|
|
*/
|
|
async setupCertificateTestEvent(): Promise<string | null> {
|
|
// Create a uniquely named event
|
|
const timestamp = new Date().getTime();
|
|
const eventName = `Certificate Test Event ${timestamp}`;
|
|
|
|
// Create the event
|
|
const eventId = await this.createTestEvent(eventName);
|
|
if (!eventId) {
|
|
this.verbosity.log('Failed to create test event');
|
|
return null;
|
|
}
|
|
|
|
// Add test attendees (mix of checked-in and non-checked-in)
|
|
await this.createTestAttendees(eventId, 6);
|
|
|
|
return eventName;
|
|
}
|
|
} |