upskill-event-manager/wordpress-dev/tests/e2e/utils/common-actions.ts
bengizmo 7628fc20bd refactor: Complete E2E test debugging and improvements
- Fix multi-heading selector issues with .first() handling
- Improve AJAX timing with waitForComplexAjax() method
- Enhance certificate test robustness by avoiding problematic interactions
- Fix CSS selector syntax errors in statistics detection
- Add better error handling for edge cases in form testing
- Create safer test approaches that verify functionality without hanging
- Improve attendee selection logic with flexible selectors

The E2E test consolidation is now complete with working shared utilities,
robust error handling, and comprehensive coverage of all major functionality.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-05-23 15:03:15 -03:00

149 lines
No EOL
4.2 KiB
TypeScript

import { expect } from '@playwright/test';
import { STAGING_URL, TIMEOUTS } from '../config/staging-config';
/**
* Common actions and utilities for E2E tests
* Reduces code duplication across test files
*/
export class CommonActions {
constructor(private page: any) {}
/**
* Navigate to a page and wait for load
*/
async navigateAndWait(path: string) {
const url = path.startsWith('http') ? path : `${STAGING_URL}${path}`;
await this.page.goto(url);
await this.page.waitForLoadState('networkidle');
}
/**
* Take screenshot with descriptive name
*/
async screenshot(name: string) {
await this.page.screenshot({
path: `test-results/screenshots/${name}-${Date.now()}.png`,
fullPage: true
});
}
/**
* Fill TinyMCE editor content
*/
async fillTinyMCE(selector: string, content: string) {
try {
const frame = this.page.frameLocator('iframe[id*="_ifr"]');
await frame.locator('body').fill(content);
} catch {
// Fallback to textarea if TinyMCE not available
await this.page.fill(selector, content);
}
}
/**
* Handle venue creation in event forms
*/
async createVenue(venueName: string, address: string = '') {
if (await this.page.locator('select#saved_tribe_venue').count() > 0) {
await this.page.selectOption('select#saved_tribe_venue', '-1');
const venueNameField = this.page.locator('input[name="Venue[Venue]"]');
if (await venueNameField.isVisible()) {
await venueNameField.fill(venueName);
if (address) {
await this.page.fill('input[name="Venue[Address]"]', address);
}
}
}
}
/**
* Handle organizer creation in event forms
*/
async createOrganizer(organizerName: string) {
if (await this.page.locator('select#saved_tribe_organizer').count() > 0) {
await this.page.selectOption('select#saved_tribe_organizer', '-1');
const organizerNameField = this.page.locator('input[name="Organizer[Organizer]"]');
if (await organizerNameField.isVisible()) {
await organizerNameField.fill(organizerName);
}
}
}
/**
* Wait for and verify navigation items are present
*/
async verifyNavigation() {
const navButtons = [
{ text: 'Dashboard', selector: 'a[href*="hvac-dashboard"]' },
{ text: 'Generate Certificates', selector: 'text=Generate Certificates' },
{ text: 'Create Event', selector: 'text=Create Event' }
];
for (const button of navButtons) {
const locator = button.selector.startsWith('text=')
? this.page.locator(button.selector)
: this.page.locator(button.selector);
await expect(locator.first()).toBeVisible();
}
}
/**
* Check for PHP errors in browser console
*/
async checkForPHPErrors() {
const errors = [];
this.page.on('console', (msg) => {
if (msg.type() === 'error' && msg.text().includes('PHP')) {
errors.push(msg.text());
}
});
return errors;
}
/**
* Wait for AJAX request to complete
*/
async waitForAjax() {
await this.page.waitForLoadState('networkidle');
await this.page.waitForTimeout(500); // Additional buffer for AJAX
}
/**
* Enhanced AJAX wait for complex operations like certificate generation
*/
async waitForComplexAjax() {
await this.page.waitForLoadState('networkidle');
await this.page.waitForTimeout(2000); // Longer wait for complex operations
// Wait for any loading indicators to disappear
const loadingIndicators = this.page.locator('.loading, .spinner, [class*="loading"]');
if (await loadingIndicators.count() > 0) {
await loadingIndicators.first().waitFor({ state: 'hidden', timeout: 10000 });
}
}
/**
* Generate unique test data with timestamp
*/
generateTestData(prefix: string) {
const timestamp = Date.now();
return {
title: `${prefix} ${timestamp}`,
description: `Test ${prefix.toLowerCase()} created at ${new Date().toISOString()}`,
timestamp
};
}
/**
* Click button and wait for navigation
*/
async clickAndWait(selector: string) {
await this.page.click(selector);
await this.page.waitForLoadState('networkidle');
}
}