/** * Master Trainer Dashboard Page Object * Handles all interactions with the master trainer dashboard */ const BasePage = require('../base/BasePage'); class MasterTrainerDashboard extends BasePage { constructor(page = null) { super(page); this.url = '/master-trainer/master-dashboard/'; this.title = 'Master Trainer Dashboard'; this.selectors = { // Main dashboard elements dashboardTitle: 'h1, .dashboard-title, .page-title', welcomeMessage: '.welcome-message, .dashboard-welcome', userInfo: '.user-info, .current-user', // Navigation menu navigationMenu: '.master-trainer-navigation, .dashboard-nav', menuItems: '.nav-item, .menu-item', // Dashboard cards/sections eventsOverview: '.events-overview, [data-section="events"]', trainersOverview: '.trainers-overview, [data-section="trainers"]', announcementsOverview: '.announcements-overview, [data-section="announcements"]', pendingApprovalsOverview: '.pending-approvals, [data-section="approvals"]', // Quick action buttons quickActions: '.quick-actions, .dashboard-actions', createEventBtn: 'a[href*="create-event"], .create-event-btn', manageTrainersBtn: 'a[href*="trainers"], .manage-trainers-btn', viewAnnouncementsBtn: 'a[href*="announcements"], .announcements-btn', pendingApprovalsBtn: 'a[href*="pending-approvals"], .approvals-btn', // Statistics and metrics statsContainer: '.dashboard-stats, .metrics', totalEvents: '.total-events, [data-metric="events"]', totalTrainers: '.total-trainers, [data-metric="trainers"]', pendingApprovals: '.pending-count, [data-metric="pending"]', // Master trainer specific elements importExportSection: '.import-export, [data-section="import-export"]', googleSheetsBtn: 'a[href*="google-sheets"], .google-sheets-btn', communicationTemplatesBtn: 'a[href*="communication-templates"], .templates-btn', // Common page elements logoutBtn: '.logout, a[href*="logout"]', profileLink: 'a[href*="profile"], .profile-link', settingsLink: 'a[href*="settings"], .settings-link', // Error and loading states loadingIndicator: '.loading, .spinner, .loader', errorMessage: '.error, .notice-error', successMessage: '.success, .notice-success', // Content areas mainContent: '.main-content, .dashboard-content', sidebar: '.sidebar, .dashboard-sidebar', footer: '.dashboard-footer, .footer' }; } /** * Wait for dashboard page to be fully loaded * @returns {Promise} */ async waitForPageReady() { // Wait for main dashboard elements await this.waitForElement(this.selectors.dashboardTitle); await this.waitForElement(this.selectors.mainContent); // Wait for navigation to be loaded await this.waitForElement(this.selectors.navigationMenu); // Wait for any AJAX loading to complete await this.waitForAjaxComplete(); // Wait for dashboard statistics to load try { await this.waitForElement(this.selectors.statsContainer, 5000); } catch (error) { // Statistics might not be present - continue } } /** * Get dashboard title * @returns {Promise} */ async getDashboardTitle() { return await this.getElementText(this.selectors.dashboardTitle); } /** * Check if user is properly authenticated as master trainer * @returns {Promise} */ async isAuthenticatedAsMasterTrainer() { try { await this.waitForElement(this.selectors.dashboardTitle, 10000); const title = await this.getDashboardTitle(); return title.toLowerCase().includes('master trainer'); } catch (error) { return false; } } /** * Navigate to Events Overview page * @returns {Promise} */ async navigateToEvents() { const eventsBtn = await this.page.$('a[href*="events"], .events-btn, .events-link'); if (eventsBtn) { await this.clickElement('a[href*="events"], .events-btn, .events-link'); } else { // Fallback navigation await this.page.goto(`${this.page.url().split('/master-trainer')[0]}/master-trainer/events/`); } await this.waitForPageLoad(); } /** * Navigate to Trainers Management page * @returns {Promise} */ async navigateToTrainers() { const trainersBtn = await this.page.$('a[href*="trainers"], .trainers-btn, .manage-trainers'); if (trainersBtn) { await this.clickElement('a[href*="trainers"], .trainers-btn, .manage-trainers'); } else { await this.page.goto(`${this.page.url().split('/master-trainer')[0]}/master-trainer/trainers/`); } await this.waitForPageLoad(); } /** * Navigate to Announcements page * @returns {Promise} */ async navigateToAnnouncements() { const announcementsBtn = await this.page.$('a[href*="announcements"], .announcements-btn'); if (announcementsBtn) { await this.clickElement('a[href*="announcements"], .announcements-btn'); } else { await this.page.goto(`${this.page.url().split('/master-trainer')[0]}/master-trainer/announcements/`); } await this.waitForPageLoad(); } /** * Navigate to Pending Approvals page * @returns {Promise} */ async navigateToPendingApprovals() { const approvalsBtn = await this.page.$('a[href*="pending-approvals"], .approvals-btn, .pending-btn'); if (approvalsBtn) { await this.clickElement('a[href*="pending-approvals"], .approvals-btn, .pending-btn'); } else { await this.page.goto(`${this.page.url().split('/master-trainer')[0]}/master-trainer/pending-approvals/`); } await this.waitForPageLoad(); } /** * Navigate to Google Sheets Import/Export * @returns {Promise} */ async navigateToGoogleSheets() { const googleSheetsBtn = await this.page.$('a[href*="google-sheets"], .google-sheets-btn, .import-export-btn'); if (googleSheetsBtn) { await this.clickElement('a[href*="google-sheets"], .google-sheets-btn, .import-export-btn'); } else { await this.page.goto(`${this.page.url().split('/master-trainer')[0]}/master-trainer/google-sheets/`); } await this.waitForPageLoad(); } /** * Navigate to Communication Templates * @returns {Promise} */ async navigateToCommunicationTemplates() { const templatesBtn = await this.page.$('a[href*="communication-templates"], .templates-btn, .communication-btn'); if (templatesBtn) { await this.clickElement('a[href*="communication-templates"], .templates-btn, .communication-btn'); } else { await this.page.goto(`${this.page.url().split('/master-trainer')[0]}/master-trainer/communication-templates/`); } await this.waitForPageLoad(); } /** * Navigate to Certificate System Diagnostics * @returns {Promise} */ async navigateToCertificateFix() { const certificateBtn = await this.page.$('a[href*="certificate-fix"], .certificate-btn, .certificate-fix-btn'); if (certificateBtn) { await this.clickElement('a[href*="certificate-fix"], .certificate-btn, .certificate-fix-btn'); } else { await this.page.goto(`${this.page.url().split('/master-trainer')[0]}/master-trainer/certificate-fix/`); } await this.waitForPageLoad(); } /** * Navigate to Edit Trainer Profile * @returns {Promise} */ async navigateToEditTrainerProfile() { const editProfileBtn = await this.page.$('a[href*="edit-trainer-profile"], .edit-profile-btn, .edit-trainer-btn'); if (editProfileBtn) { await this.clickElement('a[href*="edit-trainer-profile"], .edit-profile-btn, .edit-trainer-btn'); } else { await this.page.goto(`${this.page.url().split('/master-trainer')[0]}/master-trainer/edit-trainer-profile/`); } await this.waitForPageLoad(); } /** * Get dashboard statistics * @returns {Promise} */ async getDashboardStats() { const stats = {}; try { // Total events if (await this.hasElement(this.selectors.totalEvents)) { const eventsText = await this.getElementText(this.selectors.totalEvents); stats.totalEvents = this.extractNumber(eventsText); } // Total trainers if (await this.hasElement(this.selectors.totalTrainers)) { const trainersText = await this.getElementText(this.selectors.totalTrainers); stats.totalTrainers = this.extractNumber(trainersText); } // Pending approvals if (await this.hasElement(this.selectors.pendingApprovals)) { const pendingText = await this.getElementText(this.selectors.pendingApprovals); stats.pendingApprovals = this.extractNumber(pendingText); } } catch (error) { console.warn('Failed to get dashboard stats:', error.message); } return stats; } /** * Check if navigation menu is present and functional * @returns {Promise} */ async hasNavigationMenu() { try { await this.waitForElement(this.selectors.navigationMenu, 5000); const menuItems = await this.page.$$(this.selectors.menuItems); return menuItems.length > 0; } catch (error) { return false; } } /** * Get all available navigation menu items * @returns {Promise} */ async getNavigationMenuItems() { const menuItems = []; try { const items = await this.page.$$(this.selectors.menuItems); for (const item of items) { const text = await item.textContent(); const href = await item.getAttribute('href'); menuItems.push({ text: text.trim(), href }); } } catch (error) { console.warn('Failed to get menu items:', error.message); } return menuItems; } /** * Check if specific dashboard section is visible * @param {string} sectionName - Name of section (events, trainers, announcements, etc.) * @returns {Promise} */ async isDashboardSectionVisible(sectionName) { const sectionSelectors = { 'events': this.selectors.eventsOverview, 'trainers': this.selectors.trainersOverview, 'announcements': this.selectors.announcementsOverview, 'approvals': this.selectors.pendingApprovalsOverview, 'import-export': this.selectors.importExportSection }; const selector = sectionSelectors[sectionName]; if (!selector) return false; return await this.isElementVisible(selector); } /** * Wait for dashboard loading to complete * @returns {Promise} */ async waitForDashboardLoaded() { // Wait for loading indicators to disappear try { await this.waitForElementHidden(this.selectors.loadingIndicator, 10000); } catch (error) { // Loading indicator might not be present } // Ensure main content is visible await this.waitForElement(this.selectors.mainContent); // Wait for any AJAX to complete await this.waitForAjaxComplete(); } /** * Extract number from text string * @param {string} text - Text containing a number * @returns {number|null} * @private */ extractNumber(text) { const match = text.match(/\d+/); return match ? parseInt(match[0], 10) : null; } /** * Logout from master trainer dashboard * @returns {Promise} */ async logout() { const logoutBtn = await this.page.$(this.selectors.logoutBtn); if (logoutBtn) { await this.clickElement(this.selectors.logoutBtn); } else { // Fallback logout await this.page.goto('/wp-login.php?action=logout'); } // Wait for redirect to login page await this.page.waitForURL(url => url.includes('login') || url.includes('wp-login'), { timeout: 10000 } ); } /** * Take screenshot of dashboard * @param {string} filename - Screenshot filename * @returns {Promise} */ async takeScreenshot(filename = 'master-trainer-dashboard.png') { await this.waitForDashboardLoaded(); return await super.takeScreenshot(filename); } } module.exports = MasterTrainerDashboard;