/** * Trainer Dashboard Page Object * Handles all interactions with the regular trainer dashboard */ const BasePage = require('../base/BasePage'); class TrainerDashboard extends BasePage { constructor(page = null) { super(page); this.url = '/trainer/dashboard/'; this.title = '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: '.trainer-navigation, .dashboard-nav', menuItems: '.nav-item, .menu-item', // Dashboard sections eventsSection: '.events-section, [data-section="events"]', profileSection: '.profile-section, [data-section="profile"]', venueSection: '.venue-section, [data-section="venues"]', organizerSection: '.organizer-section, [data-section="organizers"]', // Quick action buttons quickActions: '.quick-actions, .dashboard-actions', createEventBtn: 'a[href*="create-event"], .create-event-btn', manageEventsBtn: 'a[href*="events"], .manage-events-btn', profileBtn: 'a[href*="profile"], .profile-btn', venueBtn: 'a[href*="venue"], .venue-btn', organizerBtn: 'a[href*="organizer"], .organizer-btn', // Events related upcomingEvents: '.upcoming-events, .events-list', eventItems: '.event-item, .event-card', noEventsMessage: '.no-events, .empty-events', // Profile related profileStatus: '.profile-status, .trainer-status', profileCompletion: '.profile-completion, .completion-status', editProfileBtn: 'a[href*="edit-profile"], .edit-profile-btn', // Venue management venueList: '.venue-list, .venues', addVenueBtn: 'a[href*="add-venue"], .add-venue-btn', manageVenuesBtn: 'a[href*="venue/manage"], .manage-venues-btn', // Training leads trainingLeadsBtn: 'a[href*="training-leads"], .training-leads-btn', leadsSection: '.training-leads, [data-section="leads"]', // Common elements logoutBtn: '.logout, a[href*="logout"]', settingsLink: 'a[href*="settings"], .settings-link', helpLink: 'a[href*="help"], .help-link', // Error and loading states loadingIndicator: '.loading, .spinner, .loader', errorMessage: '.error, .notice-error', successMessage: '.success, .notice-success', // Layout elements mainContent: '.main-content, .dashboard-content', sidebar: '.sidebar, .dashboard-sidebar', breadcrumbs: '.breadcrumbs, .breadcrumb-nav' }; } /** * 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(); } /** * Get dashboard title * @returns {Promise} */ async getDashboardTitle() { return await this.getElementText(this.selectors.dashboardTitle); } /** * Check if user is properly authenticated as trainer * @returns {Promise} */ async isAuthenticatedAsTrainer() { try { await this.waitForElement(this.selectors.dashboardTitle, 10000); const title = await this.getDashboardTitle(); return title.toLowerCase().includes('trainer') && !title.toLowerCase().includes('master trainer'); } catch (error) { return false; } } /** * Navigate to Create Event page * @returns {Promise} */ async navigateToCreateEvent() { const createBtn = await this.page.$(this.selectors.createEventBtn); if (createBtn) { await this.clickElement(this.selectors.createEventBtn); } else { await this.page.goto(`${this.page.url().split('/trainer')[0]}/trainer/create-event/`); } await this.waitForPageLoad(); } /** * Navigate to Manage Events page * @returns {Promise} */ async navigateToManageEvents() { const manageBtn = await this.page.$(this.selectors.manageEventsBtn); if (manageBtn) { await this.clickElement(this.selectors.manageEventsBtn); } else { await this.page.goto(`${this.page.url().split('/trainer')[0]}/trainer/events/`); } await this.waitForPageLoad(); } /** * Navigate to Profile page * @returns {Promise} */ async navigateToProfile() { const profileBtn = await this.page.$(this.selectors.profileBtn); if (profileBtn) { await this.clickElement(this.selectors.profileBtn); } else { await this.page.goto(`${this.page.url().split('/trainer')[0]}/trainer/profile/`); } await this.waitForPageLoad(); } /** * Navigate to Venue Management * @returns {Promise} */ async navigateToVenueManagement() { const venueBtn = await this.page.$(this.selectors.venueBtn); if (venueBtn) { await this.clickElement(this.selectors.venueBtn); } else { await this.page.goto(`${this.page.url().split('/trainer')[0]}/trainer/venue/manage/`); } await this.waitForPageLoad(); } /** * Navigate to Organizer Management * @returns {Promise} */ async navigateToOrganizerManagement() { const organizerBtn = await this.page.$(this.selectors.organizerBtn); if (organizerBtn) { await this.clickElement(this.selectors.organizerBtn); } else { await this.page.goto(`${this.page.url().split('/trainer')[0]}/trainer/organizer/manage/`); } await this.waitForPageLoad(); } /** * Navigate to Training Leads * @returns {Promise} */ async navigateToTrainingLeads() { const leadsBtn = await this.page.$(this.selectors.trainingLeadsBtn); if (leadsBtn) { await this.clickElement(this.selectors.trainingLeadsBtn); } else { await this.page.goto(`${this.page.url().split('/trainer')[0]}/trainer/profile/training-leads/`); } await this.waitForPageLoad(); } /** * Get list of upcoming events * @returns {Promise} */ async getUpcomingEvents() { const events = []; try { if (await this.hasElement(this.selectors.noEventsMessage)) { return events; // No events found } const eventItems = await this.page.$$(this.selectors.eventItems); for (const item of eventItems) { const title = await item.$eval('.event-title, .title, h3, h4', el => el.textContent.trim()); const date = await item.$eval('.event-date, .date', el => el.textContent.trim()).catch(() => null); const location = await item.$eval('.event-location, .location', el => el.textContent.trim()).catch(() => null); events.push({ title, date, location }); } } catch (error) { console.warn('Failed to get upcoming events:', error.message); } return events; } /** * Check profile completion status * @returns {Promise} */ async getProfileStatus() { const status = { isComplete: false, completionPercentage: 0, missingFields: [] }; try { if (await this.hasElement(this.selectors.profileCompletion)) { const completionText = await this.getElementText(this.selectors.profileCompletion); const percentMatch = completionText.match(/(\d+)%/); if (percentMatch) { status.completionPercentage = parseInt(percentMatch[1], 10); status.isComplete = status.completionPercentage === 100; } } // Check for any missing field indicators const missingFieldElements = await this.page.$$('.missing-field, .incomplete-field'); for (const element of missingFieldElements) { const fieldName = await element.textContent(); status.missingFields.push(fieldName.trim()); } } catch (error) { console.warn('Failed to get profile status:', error.message); } return status; } /** * 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, profile, venue, etc.) * @returns {Promise} */ async isDashboardSectionVisible(sectionName) { const sectionSelectors = { 'events': this.selectors.eventsSection, 'profile': this.selectors.profileSection, 'venue': this.selectors.venueSection, 'organizer': this.selectors.organizerSection, 'leads': this.selectors.leadsSection }; 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(); } /** * Check if trainer has access to specific functionality * @param {string} functionality - Name of functionality to check * @returns {Promise} */ async hasAccessTo(functionality) { const accessSelectors = { 'createEvents': this.selectors.createEventBtn, 'manageVenues': this.selectors.venueBtn, 'manageOrganizers': this.selectors.organizerBtn, 'trainingLeads': this.selectors.trainingLeadsBtn, 'editProfile': this.selectors.editProfileBtn }; const selector = accessSelectors[functionality]; if (!selector) return false; return await this.hasElement(selector); } /** * Logout from 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 = 'trainer-dashboard.png') { await this.waitForDashboardLoaded(); return await super.takeScreenshot(filename); } } module.exports = TrainerDashboard;