/** * Trainer Dashboard Page Object Model * * Handles trainer dashboard functionality with WordPress integration: * - Navigation and menu interactions * - Dashboard widgets and statistics * - Quick actions and forms * - Event management shortcuts * * @package HVAC_Community_Events * @version 2.0.0 * @created 2025-08-27 */ const BasePage = require('./BasePage'); const { expect } = require('@playwright/test'); class TrainerDashboard extends BasePage { constructor(page) { super(page); // Dashboard-specific selectors this.selectors = { // Main dashboard elements dashboard: [ 'trainer-dashboard', '.hvac-trainer-dashboard', '.trainer-dashboard', '[data-page="trainer-dashboard"]' ], // Navigation elements navigation: [ 'trainer-nav', '.hvac-trainer-nav', '.trainer-navigation', 'nav.trainer-nav' ], // Dashboard widgets widgets: { eventCount: [ 'event-count-widget', '.event-count', '[data-widget="event-count"]', '.dashboard-stat.events' ], upcomingEvents: [ 'upcoming-events', '.upcoming-events-widget', '[data-widget="upcoming-events"]' ], recentActivity: [ 'recent-activity', '.recent-activity-widget', '[data-widget="recent-activity"]' ], statistics: [ 'trainer-stats', '.trainer-statistics', '.dashboard-statistics' ] }, // Quick action buttons actions: { createEvent: [ 'create-event-btn', 'a[href*="/create-event"]', '.create-event-button', 'text=Create Event' ], manageEvents: [ 'manage-events-btn', 'a[href*="/manage-events"]', '.manage-events-button', 'text=Manage Events' ], editProfile: [ 'edit-profile-btn', 'a[href*="/profile/edit"]', '.edit-profile-button', 'text=Edit Profile' ], viewProfile: [ 'view-profile-btn', 'a[href*="/profile"]', '.view-profile-button', 'text=View Profile' ] }, // Breadcrumb navigation breadcrumb: [ '.hvac-breadcrumb', '.breadcrumb', '[data-testid="breadcrumb"]' ], // Welcome message welcomeMessage: [ 'welcome-message', '.welcome-message', '.trainer-welcome' ], // Menu items menuItems: { dashboard: 'a[href*="/trainer/dashboard"]', events: 'a[href*="/trainer/events"], text=My Events', createEvent: 'a[href*="/create-event"], text=Create Event', profile: 'a[href*="/profile"], text=Profile', venues: 'a[href*="/venues"], text=Venues', organizers: 'a[href*="/organizers"], text=Organizers', trainingLeads: 'a[href*="/training-leads"], text=Training Leads', resources: 'a[href*="/resources"], text=Resources', documentation: 'a[href*="/documentation"], text=Documentation', announcements: 'a[href*="/announcements"], text=Announcements' } }; this.urls = { dashboard: '/trainer/dashboard/', events: '/trainer/events/', createEvent: '/trainer/create-event/', profile: '/trainer/profile/', editProfile: '/trainer/profile/edit/', venues: '/trainer/venues/', organizers: '/trainer/organizers/', trainingLeads: '/trainer/training-leads/', documentation: '/trainer/documentation/' }; } /** * Navigate to trainer dashboard */ async navigate() { await this.goto(this.urls.dashboard); await this.waitForDashboardLoad(); } /** * Wait for dashboard to fully load */ async waitForDashboardLoad() { // Wait for main dashboard container await this.waitForVisible(this.selectors.dashboard); // Wait for navigation to be present await this.waitForVisible(this.selectors.navigation); // Wait for WordPress and AJAX to complete await this.waitForWordPressReady(); await this.waitForAjax(); console.log('✅ Trainer dashboard loaded'); } /** * Verify dashboard is displayed correctly */ async verifyDashboard() { // Check main dashboard container await expect(this.locator(this.selectors.dashboard)).toBeVisible(); // Check breadcrumb if (await this.isVisible(this.selectors.breadcrumb)) { await this.verifyBreadcrumbs(['Dashboard']); } // Check navigation menu await expect(this.locator(this.selectors.navigation)).toBeVisible(); // Check welcome message if present if (await this.isVisible(this.selectors.welcomeMessage)) { console.log('✅ Welcome message displayed'); } console.log('✅ Dashboard verification complete'); } /** * Get dashboard statistics */ async getDashboardStats() { const stats = {}; // Get event count if visible if (await this.isVisible(this.selectors.widgets.eventCount)) { const eventCountText = await this.getText(this.selectors.widgets.eventCount); stats.eventCount = this.extractNumber(eventCountText); } // Get upcoming events count if (await this.isVisible(this.selectors.widgets.upcomingEvents)) { const upcomingEventsCount = await this.page .locator(`${this.selectors.widgets.upcomingEvents.join(', ')} .event-item`) .count(); stats.upcomingEvents = upcomingEventsCount; } console.log('📊 Dashboard stats:', stats); return stats; } /** * Navigate to create event page */ async goToCreateEvent() { await this.click(this.selectors.actions.createEvent, { waitForNavigation: true }); await this.waitForUrl('**/create-event**'); console.log('🔗 Navigated to Create Event page'); } /** * Navigate to manage events page */ async goToManageEvents() { await this.click(this.selectors.actions.manageEvents, { waitForNavigation: true }); await this.waitForUrl('**/events**'); console.log('🔗 Navigated to Manage Events page'); } /** * Navigate to profile page */ async goToProfile() { await this.click(this.selectors.actions.viewProfile, { waitForNavigation: true }); await this.waitForUrl('**/profile**'); console.log('🔗 Navigated to Profile page'); } /** * Navigate to edit profile page */ async goToEditProfile() { await this.click(this.selectors.actions.editProfile, { waitForNavigation: true }); await this.waitForUrl('**/profile/edit**'); console.log('🔗 Navigated to Edit Profile page'); } /** * Use navigation menu to go to specific section */ async navigateToSection(section) { const menuItem = this.selectors.menuItems[section]; if (!menuItem) { throw new Error(`Unknown navigation section: ${section}`); } // Check if navigation menu is visible if (await this.isVisible('.hvac-menu-toggle, .mobile-menu-toggle')) { // Mobile menu - open it first await this.click('.hvac-menu-toggle, .mobile-menu-toggle'); await this.waitForVisible('.hvac-menu.open, .mobile-menu.open'); } // Click menu item await this.click(menuItem, { waitForNavigation: true }); // Wait for page to load const expectedUrl = this.urls[section]; if (expectedUrl) { await this.waitForUrl(`**${expectedUrl}**`); } console.log(`🔗 Navigated to: ${section}`); } /** * Check for announcements */ async checkAnnouncements() { const announcementSelectors = [ '.hvac-announcements', '.trainer-announcements', '[data-widget="announcements"]', '.dashboard-announcements' ]; for (const selector of announcementSelectors) { if (await this.isVisible(selector)) { const announcementCount = await this.page.locator(`${selector} .announcement`).count(); console.log(`📢 Found ${announcementCount} announcements`); return announcementCount; } } return 0; } /** * Get recent activity items */ async getRecentActivity() { if (!await this.isVisible(this.selectors.widgets.recentActivity)) { return []; } const activityItems = await this.page .locator(`${this.selectors.widgets.recentActivity.join(', ')} .activity-item`) .allTextContents(); console.log(`📋 Found ${activityItems.length} recent activity items`); return activityItems; } /** * Search functionality (if available) */ async search(query) { const searchSelectors = [ '[data-testid="search-input"]', '.dashboard-search input', 'input[name="search"]', '.search-box input' ]; for (const selector of searchSelectors) { if (await this.isVisible(selector)) { await this.fill(selector, query); await this.page.keyboard.press('Enter'); await this.waitForAjax(); console.log(`🔍 Searched for: ${query}`); return true; } } console.log('⚠️ Search functionality not found'); return false; } /** * Quick actions on dashboard */ async performQuickAction(action) { const actionHandlers = { 'create-event': () => this.goToCreateEvent(), 'manage-events': () => this.goToManageEvents(), 'edit-profile': () => this.goToEditProfile(), 'view-profile': () => this.goToProfile(), 'view-venues': () => this.navigateToSection('venues'), 'view-organizers': () => this.navigateToSection('organizers'), 'view-training-leads': () => this.navigateToSection('trainingLeads') }; const handler = actionHandlers[action]; if (!handler) { throw new Error(`Unknown quick action: ${action}`); } await handler(); console.log(`⚡ Performed quick action: ${action}`); } /** * Verify trainer has access to expected dashboard elements */ async verifyTrainerAccess() { // Check that we're authenticated as trainer await this.verifyUserRole('trainer'); // Check essential navigation items const essentialItems = ['dashboard', 'events', 'profile']; for (const item of essentialItems) { const menuItem = this.selectors.menuItems[item]; await expect(this.locator(menuItem)).toBeVisible(); } // Check that we can't see admin-only elements const adminOnlySelectors = [ '.master-trainer-only', '.admin-only', 'a[href*="/master-trainer/"]', 'a[href*="/wp-admin/"]' ]; for (const selector of adminOnlySelectors) { await expect(this.locator(selector)).not.toBeVisible(); } console.log('✅ Trainer access verification complete'); } /** * Get dashboard page title */ async getPageTitle() { return await this.page.title(); } /** * Check if dashboard has mobile responsive layout */ async checkMobileResponsiveness() { // Set mobile viewport await this.page.setViewportSize({ width: 375, height: 667 }); // Check if mobile menu toggle is visible const hasMobileMenu = await this.isVisible('.hvac-menu-toggle, .mobile-menu-toggle'); // Check if navigation is adapted for mobile const hasMobileNav = await this.isVisible('.hvac-nav-mobile, .mobile-navigation'); // Reset to desktop viewport await this.page.setViewportSize({ width: this.config.get('browser.viewport.width'), height: this.config.get('browser.viewport.height') }); return { hasMobileMenu, hasMobileNav, isMobileResponsive: hasMobileMenu || hasMobileNav }; } /** * Extract number from text (helper method) */ extractNumber(text) { const match = text.match(/\d+/); return match ? parseInt(match[0], 10) : 0; } /** * Wait for specific widget to load */ async waitForWidget(widgetName) { const widget = this.selectors.widgets[widgetName]; if (!widget) { throw new Error(`Unknown widget: ${widgetName}`); } await this.waitForVisible(widget); await this.waitForAjax(); console.log(`📊 Widget loaded: ${widgetName}`); } /** * Take screenshot of full dashboard */ async screenshotDashboard() { return await this.takeScreenshot('trainer-dashboard', { fullPage: true }); } } module.exports = TrainerDashboard;