Some checks are pending
HVAC Plugin CI/CD Pipeline / Security Analysis (push) Waiting to run
HVAC Plugin CI/CD Pipeline / Code Quality & Standards (push) Waiting to run
HVAC Plugin CI/CD Pipeline / Unit Tests (push) Waiting to run
HVAC Plugin CI/CD Pipeline / Integration Tests (push) Waiting to run
HVAC Plugin CI/CD Pipeline / Deploy to Staging (push) Blocked by required conditions
HVAC Plugin CI/CD Pipeline / Deploy to Production (push) Blocked by required conditions
HVAC Plugin CI/CD Pipeline / Notification (push) Blocked by required conditions
Security Monitoring & Compliance / Dependency Vulnerability Scan (push) Waiting to run
Security Monitoring & Compliance / Secrets & Credential Scan (push) Waiting to run
Security Monitoring & Compliance / WordPress Security Analysis (push) Waiting to run
Security Monitoring & Compliance / Static Code Security Analysis (push) Waiting to run
Security Monitoring & Compliance / Security Compliance Validation (push) Waiting to run
Security Monitoring & Compliance / Security Summary Report (push) Blocked by required conditions
Security Monitoring & Compliance / Security Team Notification (push) Blocked by required conditions
- Add 90+ test files including E2E, unit, and integration tests - Implement Page Object Model (POM) architecture - Add Docker testing environment with comprehensive services - Include modernized test framework with error recovery - Add specialized test suites for master trainer and trainer workflows - Update .gitignore to properly track test infrastructure 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
353 lines
No EOL
12 KiB
JavaScript
353 lines
No EOL
12 KiB
JavaScript
/**
|
|
* Master Trainer Events Management Page Object
|
|
* Handles interactions with the master trainer events management page
|
|
*/
|
|
|
|
const BasePage = require('../base/BasePage');
|
|
|
|
class MasterTrainerEvents extends BasePage {
|
|
constructor(page = null) {
|
|
super(page);
|
|
this.url = '/master-trainer/events/';
|
|
this.title = 'Events Management';
|
|
|
|
this.selectors = {
|
|
// Main page elements
|
|
pageTitle: 'h1, .page-title, .events-title',
|
|
eventsContainer: '.events-container, .events-list, .events-table',
|
|
|
|
// Events list and table
|
|
eventsTable: 'table.events-table, .events-grid',
|
|
eventRows: 'tr.event-row, .event-item',
|
|
eventTitle: '.event-title, .event-name',
|
|
eventDate: '.event-date, .event-start-date',
|
|
eventStatus: '.event-status, .status',
|
|
eventTrainer: '.event-trainer, .trainer-name',
|
|
eventVenue: '.event-venue, .venue-name',
|
|
|
|
// Action buttons
|
|
createEventBtn: 'a[href*="create"], .create-event, .add-event',
|
|
editEventBtn: 'a[href*="edit"], .edit-event, .event-edit',
|
|
deleteEventBtn: 'a[href*="delete"], .delete-event, .event-delete',
|
|
viewEventBtn: 'a[href*="view"], .view-event, .event-view',
|
|
|
|
// Bulk actions
|
|
bulkActionsSelect: 'select[name="bulk-action"], .bulk-actions select',
|
|
bulkApplyBtn: '.bulk-apply, .apply-bulk-action',
|
|
selectAllCheckbox: 'input[type="checkbox"].select-all',
|
|
eventCheckboxes: 'input[type="checkbox"].event-select',
|
|
|
|
// Filters and search
|
|
searchInput: 'input[type="search"], .search-events, #event-search',
|
|
searchBtn: '.search-btn, .search-submit',
|
|
statusFilter: 'select.status-filter, #status-filter',
|
|
trainerFilter: 'select.trainer-filter, #trainer-filter',
|
|
dateFilter: 'input.date-filter, #date-filter',
|
|
venueFilter: 'select.venue-filter, #venue-filter',
|
|
clearFiltersBtn: '.clear-filters, .reset-filters',
|
|
|
|
// Event statistics and overview
|
|
eventStats: '.event-stats, .events-statistics',
|
|
totalEvents: '.total-events, [data-metric="total"]',
|
|
upcomingEvents: '.upcoming-events, [data-metric="upcoming"]',
|
|
pastEvents: '.past-events, [data-metric="past"]',
|
|
cancelledEvents: '.cancelled-events, [data-metric="cancelled"]',
|
|
|
|
// Event categories and types
|
|
categoryFilter: 'select.category-filter, #category-filter',
|
|
eventTypes: '.event-types, .type-filter',
|
|
|
|
// Pagination
|
|
pagination: '.pagination, .page-navigation',
|
|
prevPageBtn: '.prev-page, .previous',
|
|
nextPageBtn: '.next-page, .next',
|
|
pageNumbers: '.page-numbers a',
|
|
|
|
// Export and reporting
|
|
exportBtn: '.export-events, .download-events',
|
|
reportingBtn: '.event-reports, .reporting',
|
|
|
|
// Loading and status indicators
|
|
loadingIndicator: '.loading, .spinner',
|
|
errorMessage: '.error-message, .notice-error',
|
|
successMessage: '.success-message, .notice-success',
|
|
emptyState: '.no-events, .events-empty'
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Wait for events page to be fully loaded
|
|
*/
|
|
async waitForPageReady() {
|
|
await this.waitForElement(this.selectors.pageTitle);
|
|
await this.waitForAjaxComplete();
|
|
|
|
// Wait for events container or empty state
|
|
try {
|
|
await Promise.race([
|
|
this.waitForElement(this.selectors.eventsContainer, 10000),
|
|
this.waitForElement(this.selectors.emptyState, 10000)
|
|
]);
|
|
} catch (error) {
|
|
console.warn('Events container or empty state not found, continuing...');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get all events from the current page
|
|
*/
|
|
async getEventsList() {
|
|
const events = [];
|
|
const eventRows = await this.page.$$(this.selectors.eventRows);
|
|
|
|
for (const row of eventRows) {
|
|
const event = {
|
|
title: await this.getTextFromElement(row, this.selectors.eventTitle),
|
|
date: await this.getTextFromElement(row, this.selectors.eventDate),
|
|
status: await this.getTextFromElement(row, this.selectors.eventStatus),
|
|
trainer: await this.getTextFromElement(row, this.selectors.eventTrainer),
|
|
venue: await this.getTextFromElement(row, this.selectors.eventVenue)
|
|
};
|
|
events.push(event);
|
|
}
|
|
|
|
return events;
|
|
}
|
|
|
|
/**
|
|
* Get event statistics from the page
|
|
*/
|
|
async getEventStatistics() {
|
|
const stats = {};
|
|
|
|
try {
|
|
if (await this.hasElement(this.selectors.totalEvents)) {
|
|
const totalText = await this.getElementText(this.selectors.totalEvents);
|
|
stats.total = this.extractNumber(totalText);
|
|
}
|
|
|
|
if (await this.hasElement(this.selectors.upcomingEvents)) {
|
|
const upcomingText = await this.getElementText(this.selectors.upcomingEvents);
|
|
stats.upcoming = this.extractNumber(upcomingText);
|
|
}
|
|
|
|
if (await this.hasElement(this.selectors.pastEvents)) {
|
|
const pastText = await this.getElementText(this.selectors.pastEvents);
|
|
stats.past = this.extractNumber(pastText);
|
|
}
|
|
|
|
if (await this.hasElement(this.selectors.cancelledEvents)) {
|
|
const cancelledText = await this.getElementText(this.selectors.cancelledEvents);
|
|
stats.cancelled = this.extractNumber(cancelledText);
|
|
}
|
|
} catch (error) {
|
|
console.warn('Failed to get event statistics:', error.message);
|
|
}
|
|
|
|
return stats;
|
|
}
|
|
|
|
/**
|
|
* Search for events by term
|
|
*/
|
|
async searchEvents(searchTerm) {
|
|
if (await this.hasElement(this.selectors.searchInput)) {
|
|
await this.fillField(this.selectors.searchInput, searchTerm);
|
|
|
|
if (await this.hasElement(this.selectors.searchBtn)) {
|
|
await this.clickElement(this.selectors.searchBtn);
|
|
} else {
|
|
// Submit by pressing Enter
|
|
await this.page.keyboard.press('Enter');
|
|
}
|
|
|
|
await this.waitForAjaxComplete();
|
|
await this.waitForPageReady();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filter events by status
|
|
*/
|
|
async filterByStatus(status) {
|
|
if (await this.hasElement(this.selectors.statusFilter)) {
|
|
await this.selectOption(this.selectors.statusFilter, status);
|
|
await this.waitForAjaxComplete();
|
|
await this.waitForPageReady();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filter events by trainer
|
|
*/
|
|
async filterByTrainer(trainerId) {
|
|
if (await this.hasElement(this.selectors.trainerFilter)) {
|
|
await this.selectOption(this.selectors.trainerFilter, trainerId);
|
|
await this.waitForAjaxComplete();
|
|
await this.waitForPageReady();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear all filters
|
|
*/
|
|
async clearAllFilters() {
|
|
if (await this.hasElement(this.selectors.clearFiltersBtn)) {
|
|
await this.clickElement(this.selectors.clearFiltersBtn);
|
|
await this.waitForAjaxComplete();
|
|
await this.waitForPageReady();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Navigate to create event page
|
|
*/
|
|
async createNewEvent() {
|
|
if (await this.hasElement(this.selectors.createEventBtn)) {
|
|
await this.clickElement(this.selectors.createEventBtn);
|
|
await this.waitForPageLoad();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Edit an event by index or title
|
|
*/
|
|
async editEvent(identifier) {
|
|
const eventRows = await this.page.$$(this.selectors.eventRows);
|
|
|
|
if (typeof identifier === 'number' && eventRows[identifier]) {
|
|
// Edit by index
|
|
const editBtn = await eventRows[identifier].$(this.selectors.editEventBtn);
|
|
if (editBtn) {
|
|
await editBtn.click();
|
|
await this.waitForPageLoad();
|
|
return true;
|
|
}
|
|
} else if (typeof identifier === 'string') {
|
|
// Edit by event title
|
|
for (const row of eventRows) {
|
|
const titleElement = await row.$(this.selectors.eventTitle);
|
|
if (titleElement) {
|
|
const title = await titleElement.textContent();
|
|
if (title.trim().includes(identifier)) {
|
|
const editBtn = await row.$(this.selectors.editEventBtn);
|
|
if (editBtn) {
|
|
await editBtn.click();
|
|
await this.waitForPageLoad();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Perform bulk actions on selected events
|
|
*/
|
|
async performBulkAction(action, eventIndices = []) {
|
|
// Select events by index
|
|
const eventRows = await this.page.$$(this.selectors.eventRows);
|
|
|
|
for (const index of eventIndices) {
|
|
if (eventRows[index]) {
|
|
const checkbox = await eventRows[index].$(this.selectors.eventCheckboxes);
|
|
if (checkbox) {
|
|
await checkbox.click();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Select bulk action
|
|
if (await this.hasElement(this.selectors.bulkActionsSelect)) {
|
|
await this.selectOption(this.selectors.bulkActionsSelect, action);
|
|
|
|
if (await this.hasElement(this.selectors.bulkApplyBtn)) {
|
|
await this.clickElement(this.selectors.bulkApplyBtn);
|
|
await this.waitForAjaxComplete();
|
|
await this.waitForPageReady();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Select all events on current page
|
|
*/
|
|
async selectAllEvents() {
|
|
if (await this.hasElement(this.selectors.selectAllCheckbox)) {
|
|
await this.clickElement(this.selectors.selectAllCheckbox);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Export events data
|
|
*/
|
|
async exportEvents() {
|
|
if (await this.hasElement(this.selectors.exportBtn)) {
|
|
await this.clickElement(this.selectors.exportBtn);
|
|
// Wait for download to start
|
|
await this.page.waitForTimeout(2000);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if events page has any events
|
|
*/
|
|
async hasEvents() {
|
|
return await this.hasElement(this.selectors.eventRows);
|
|
}
|
|
|
|
/**
|
|
* Check if page is showing empty state
|
|
*/
|
|
async isEmptyState() {
|
|
return await this.isElementVisible(this.selectors.emptyState);
|
|
}
|
|
|
|
/**
|
|
* Get available event management features
|
|
*/
|
|
async getAvailableFeatures() {
|
|
return {
|
|
canCreate: await this.hasElement(this.selectors.createEventBtn),
|
|
canSearch: await this.hasElement(this.selectors.searchInput),
|
|
canFilter: await this.hasElement(this.selectors.statusFilter),
|
|
canBulkAction: await this.hasElement(this.selectors.bulkActionsSelect),
|
|
canExport: await this.hasElement(this.selectors.exportBtn),
|
|
hasStatistics: await this.hasElement(this.selectors.eventStats)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Helper method to get text from child element
|
|
*/
|
|
async getTextFromElement(parentElement, selector) {
|
|
try {
|
|
const element = await parentElement.$(selector);
|
|
return element ? await element.textContent() : '';
|
|
} catch (error) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extract number from text string
|
|
*/
|
|
extractNumber(text) {
|
|
const match = text.match(/\d+/);
|
|
return match ? parseInt(match[0], 10) : 0;
|
|
}
|
|
}
|
|
|
|
module.exports = MasterTrainerEvents; |