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>
344 lines
No EOL
12 KiB
JavaScript
344 lines
No EOL
12 KiB
JavaScript
/**
|
|
* 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<void>}
|
|
*/
|
|
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<string>}
|
|
*/
|
|
async getDashboardTitle() {
|
|
return await this.getElementText(this.selectors.dashboardTitle);
|
|
}
|
|
|
|
/**
|
|
* Check if user is properly authenticated as master trainer
|
|
* @returns {Promise<boolean>}
|
|
*/
|
|
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<void>}
|
|
*/
|
|
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<void>}
|
|
*/
|
|
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<void>}
|
|
*/
|
|
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<void>}
|
|
*/
|
|
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<void>}
|
|
*/
|
|
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<void>}
|
|
*/
|
|
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();
|
|
}
|
|
|
|
/**
|
|
* Get dashboard statistics
|
|
* @returns {Promise<Object>}
|
|
*/
|
|
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<boolean>}
|
|
*/
|
|
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<Array>}
|
|
*/
|
|
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<boolean>}
|
|
*/
|
|
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<void>}
|
|
*/
|
|
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<void>}
|
|
*/
|
|
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<string>}
|
|
*/
|
|
async takeScreenshot(filename = 'master-trainer-dashboard.png') {
|
|
await this.waitForDashboardLoaded();
|
|
return await super.takeScreenshot(filename);
|
|
}
|
|
}
|
|
|
|
module.exports = MasterTrainerDashboard; |