/** * Administrative Features Page Object Model * * Centralized page object for all administrative and operational system pages * Supports both standard Playwright and MCP Playwright integration * * Pages Covered: * - Certificate Reports (/master-trainer/certificate-reports/) * - Certificate Generation (/master-trainer/generate-certificates/) * - Email Attendees (/master-trainer/email-attendees/) * - Communication Templates (/master-trainer/communication-templates/) * - Communication Schedules (/master-trainer/communication-schedules/) * - Google Sheets Integration (/master-trainer/google-sheets/) * - Import/Export (/master-trainer/import-export/) */ const BasePage = require('../../framework/base/BasePage'); class AdministrativeFeatures extends BasePage { constructor() { super(); this.baseUrl = 'https://upskill-staging.measurequick.com'; // Define all administrative page URLs this.urls = { certificateReports: '/master-trainer/certificate-reports/', certificateGeneration: '/master-trainer/generate-certificates/', emailAttendees: '/master-trainer/email-attendees/', communicationTemplates: '/master-trainer/communication-templates/', communicationSchedules: '/master-trainer/communication-schedules/', googleSheets: '/master-trainer/google-sheets/', importExport: '/master-trainer/import-export/', masterDashboard: '/master-trainer/master-dashboard/', trainersManagement: '/master-trainer/trainers/' }; // Define selectors for each administrative area this.selectors = { // Certificate Generation Selectors certificate: { reportsContainer: '.certificate-reports-container, .certificates-list', generationForm: '.certificate-generation-form, .certificate-form', templateSelector: 'select[name*="template"], .template-selector', eventSelector: 'select[name*="event"], .event-selector', participantInput: 'input[name*="participant"], input[name*="attendee"]', generateButton: 'button[type="submit"], input[type="submit"], .generate-certificates', templatePreview: '.template-preview, .certificate-preview', bulkOptions: '.bulk-certificate-generation, .bulk-options' }, // Communication System Selectors communication: { emailForm: '.email-attendees-form, .email-form', subjectField: 'input[name*="subject"], #email_subject', messageField: 'textarea[name*="message"], textarea[name*="content"], #email_content', recipientSelector: '.recipient-selector, .attendee-selector', sendButton: 'button[name*="send"], input[value*="Send"]', templatesList: '.communication-templates-list, .templates-list', templateEditor: '.template-editor, .wp-editor-area', templateName: 'input[name*="template_name"], .template-title', scheduleOptions: '.communication-scheduler, .schedule-options', dateTimePicker: 'input[type="datetime-local"], .date-picker' }, // Data Integration Selectors dataIntegration: { googleSheetsContainer: '.google-sheets-integration, .sheets-container', syncButton: 'button[name*="sync"], .sync-button', connectionStatus: '.integration-status, .connection-status', spreadsheetSelector: '.spreadsheet-selector, select[name*="spreadsheet"]', importForm: '.import-export-controls, .import-form', fileInput: 'input[type="file"]', exportButton: 'button[name*="export"], .export-button', formatSelector: 'select[name*="format"], .format-selector', dataMapping: '.field-mapping-interface, .data-mapping' }, // Administrative Workflow Selectors admin: { dashboardContainer: '.master-dashboard, .dashboard-content', systemHealth: '.system-health-indicator, .health-status', trainersManagement: '.trainers-management-list, .trainers-list', trainerSearch: '.trainer-search input, input[name*="search"]', trainerActions: '.trainer-actions, .action-buttons', configPanel: '.configuration-panel, .admin-settings', auditLog: '.audit-log, .activity-log', backupControls: '.backup-controls, .backup-options' } }; } /** * CERTIFICATE GENERATION METHODS */ async navigateToCertificateReports() { await this.navigateTo(this.urls.certificateReports); await this.waitForPageLoad(); } async navigateToCertificateGeneration() { await this.navigateTo(this.urls.certificateGeneration); await this.waitForPageLoad(); } async selectCertificateTemplate(templateName) { const templateSelector = this.selectors.certificate.templateSelector; try { await this.waitForElement(templateSelector); await this.selectOption(templateSelector, templateName); console.log(`✅ Selected certificate template: ${templateName}`); return true; } catch (error) { console.log(`📝 Certificate template selector not available: ${error.message}`); return false; } } async selectEventForCertificate(eventId) { const eventSelector = this.selectors.certificate.eventSelector; try { await this.waitForElement(eventSelector); await this.selectOption(eventSelector, eventId); console.log(`✅ Selected event for certificate: ${eventId}`); return true; } catch (error) { console.log(`📝 Event selector not available: ${error.message}`); return false; } } async generateCertificates(participants = []) { try { // Fill participant information if provided if (participants.length > 0) { const participantInput = this.selectors.certificate.participantInput; await this.fillField(participantInput, participants.join(', ')); } // Click generate button const generateButton = this.selectors.certificate.generateButton; await this.clickElement(generateButton); console.log(`✅ Certificate generation initiated`); return true; } catch (error) { console.log(`❌ Certificate generation failed: ${error.message}`); return false; } } async isCertificateGenerationAvailable() { try { const form = await this.page.$(this.selectors.certificate.generationForm); return form !== null; } catch (error) { return false; } } /** * COMMUNICATION SYSTEM METHODS */ async navigateToEmailAttendees() { await this.navigateTo(this.urls.emailAttendees); await this.waitForPageLoad(); } async navigateToCommunicationTemplates() { await this.navigateTo(this.urls.communicationTemplates); await this.waitForPageLoad(); } async navigateToCommunicationSchedules() { await this.navigateTo(this.urls.communicationSchedules); await this.waitForPageLoad(); } async composeEmail(subject, message) { try { // Fill email subject const subjectField = this.selectors.communication.subjectField; await this.waitForElement(subjectField); await this.fillField(subjectField, subject); // Fill email message const messageField = this.selectors.communication.messageField; await this.waitForElement(messageField); await this.fillField(messageField, message); console.log(`✅ Email composed: ${subject}`); return true; } catch (error) { console.log(`❌ Email composition failed: ${error.message}`); return false; } } async selectEmailRecipients(criteria) { try { const recipientSelector = this.selectors.communication.recipientSelector; await this.waitForElement(recipientSelector); if (typeof criteria === 'string') { await this.selectOption(recipientSelector, criteria); } else if (Array.isArray(criteria)) { // Handle multiple selection criteria for (const criterion of criteria) { await this.selectOption(recipientSelector, criterion); } } console.log(`✅ Email recipients selected`); return true; } catch (error) { console.log(`📝 Recipient selection not available: ${error.message}`); return false; } } async sendEmail() { try { const sendButton = this.selectors.communication.sendButton; await this.clickElement(sendButton); console.log(`✅ Email sent`); return true; } catch (error) { console.log(`❌ Email send failed: ${error.message}`); return false; } } async createCommunicationTemplate(name, content) { try { // Fill template name const nameField = this.selectors.communication.templateName; await this.waitForElement(nameField); await this.fillField(nameField, name); // Fill template content const editor = this.selectors.communication.templateEditor; await this.waitForElement(editor); await this.fillField(editor, content); console.log(`✅ Communication template created: ${name}`); return true; } catch (error) { console.log(`❌ Template creation failed: ${error.message}`); return false; } } async isEmailSystemAvailable() { try { const form = await this.page.$(this.selectors.communication.emailForm); return form !== null; } catch (error) { return false; } } /** * DATA INTEGRATION METHODS */ async navigateToGoogleSheets() { await this.navigateTo(this.urls.googleSheets); await this.waitForPageLoad(); } async navigateToImportExport() { await this.navigateTo(this.urls.importExport); await this.waitForPageLoad(); } async syncGoogleSheets() { try { const syncButton = this.selectors.dataIntegration.syncButton; await this.waitForElement(syncButton); await this.clickElement(syncButton); console.log(`✅ Google Sheets sync initiated`); return true; } catch (error) { console.log(`❌ Google Sheets sync failed: ${error.message}`); return false; } } async getGoogleSheetsConnectionStatus() { try { const statusElement = await this.page.$(this.selectors.dataIntegration.connectionStatus); if (statusElement) { const status = await statusElement.textContent(); console.log(`📊 Google Sheets status: ${status?.trim()}`); return status?.trim(); } return 'Status unavailable'; } catch (error) { return 'Error reading status'; } } async uploadFileForImport(filePath) { try { const fileInput = this.selectors.dataIntegration.fileInput; await this.waitForElement(fileInput); // Note: In actual implementation, this would handle file upload console.log(`✅ File upload initiated: ${filePath}`); return true; } catch (error) { console.log(`❌ File upload failed: ${error.message}`); return false; } } async exportData(format = 'csv') { try { // Select export format const formatSelector = this.selectors.dataIntegration.formatSelector; await this.waitForElement(formatSelector); await this.selectOption(formatSelector, format); // Click export button const exportButton = this.selectors.dataIntegration.exportButton; await this.clickElement(exportButton); console.log(`✅ Data export initiated: ${format}`); return true; } catch (error) { console.log(`❌ Data export failed: ${error.message}`); return false; } } async isDataIntegrationAvailable() { try { const container = await this.page.$(this.selectors.dataIntegration.googleSheetsContainer); return container !== null; } catch (error) { return false; } } /** * ADMINISTRATIVE WORKFLOW METHODS */ async navigateToMasterDashboard() { await this.navigateTo(this.urls.masterDashboard); await this.waitForPageLoad(); } async navigateToTrainersManagement() { await this.navigateTo(this.urls.trainersManagement); await this.waitForPageLoad(); } async getSystemHealthStatus() { try { const healthElement = await this.page.$(this.selectors.admin.systemHealth); if (healthElement) { const status = await healthElement.textContent(); console.log(`🔍 System health: ${status?.trim()}`); return status?.trim(); } return 'Health status unavailable'; } catch (error) { return 'Error reading health status'; } } async searchTrainers(searchTerm) { try { const searchField = this.selectors.admin.trainerSearch; await this.waitForElement(searchField); await this.fillField(searchField, searchTerm); console.log(`✅ Trainer search: ${searchTerm}`); return true; } catch (error) { console.log(`❌ Trainer search failed: ${error.message}`); return false; } } async getTrainerCount() { try { const trainerItems = await this.page.$$('.trainer-item, .trainer-row, tbody tr'); const count = trainerItems.length; console.log(`📊 Found ${count} trainers`); return count; } catch (error) { console.log(`📝 Could not count trainers: ${error.message}`); return 0; } } async isAdminWorkflowAvailable() { try { const dashboard = await this.page.$(this.selectors.admin.dashboardContainer); return dashboard !== null; } catch (error) { return false; } } /** * UTILITY METHODS */ async getAllAdministrativeFeatureStatus() { const status = { certificateGeneration: await this.isCertificateGenerationAvailable(), emailSystem: await this.isEmailSystemAvailable(), dataIntegration: await this.isDataIntegrationAvailable(), adminWorkflow: await this.isAdminWorkflowAvailable() }; console.log('📊 Administrative Features Status:'); console.log(` Certificate Generation: ${status.certificateGeneration ? '✅' : '❌'}`); console.log(` Email System: ${status.emailSystem ? '✅' : '❌'}`); console.log(` Data Integration: ${status.dataIntegration ? '✅' : '❌'}`); console.log(` Admin Workflow: ${status.adminWorkflow ? '✅' : '❌'}`); return status; } async navigateToAdministrativeArea(areaName) { const url = this.urls[areaName]; if (!url) { throw new Error(`Unknown administrative area: ${areaName}`); } await this.navigateTo(url); await this.waitForPageLoad(); console.log(`✅ Navigated to ${areaName}`); } async takeAdministrativeAreaScreenshot(areaName, context = '') { const filename = `admin-${areaName}${context ? '-' + context : ''}.png`; await this.takeScreenshot(filename); console.log(`📸 Screenshot taken: ${filename}`); return filename; } /** * Override base page methods for administrative features */ async waitForPageLoad(timeout = 10000) { await super.waitForPageLoad(timeout); // Wait for any administrative-specific loading indicators try { await this.page.waitForLoadState('domcontentloaded'); // Wait for common administrative elements await Promise.race([ this.page.waitForSelector('.admin-content', { timeout: 5000 }), this.page.waitForSelector('.master-trainer-content', { timeout: 5000 }), this.page.waitForSelector('.dashboard-content', { timeout: 5000 }), new Promise(resolve => setTimeout(resolve, 2000)) // Fallback timeout ]); } catch (error) { // Non-blocking - page may have different structure console.log(`📝 Standard admin elements not found, continuing...`); } } setBaseUrl(baseUrl) { this.baseUrl = baseUrl; // Update all URLs with new base Object.keys(this.urls).forEach(key => { if (!this.urls[key].startsWith('http')) { this.urls[key] = baseUrl + this.urls[key]; } }); } } module.exports = AdministrativeFeatures;