/** * Master Trainer E2E Test Suite - Modernized * Comprehensive end-to-end testing using the new framework architecture * * This replaces test-master-trainer-e2e.js with 90% less code duplication */ const BaseTest = require('../../framework/base/BaseTest'); const { createEnvironmentConfig } = require('../../environments/EnvironmentConfig'); const MasterTrainerDashboard = require('../../page-objects/master-trainer/MasterTrainerDashboard'); const SecurityTestFramework = require('../../utilities/security/SecurityTestFramework'); const { getTestDataManager } = require('../../data/TestDataManager'); class MasterTrainerE2ETest extends BaseTest { constructor() { super('MasterTrainerE2E'); this.envConfig = null; this.testDataManager = null; this.securityFramework = null; this.dashboardPage = null; } /** * Set up the test suite */ async setUp() { // Load environment configuration this.envConfig = createEnvironmentConfig(process.env.TEST_ENVIRONMENT || 'staging'); // Initialize with environment-specific config await super.setUp(this.envConfig.getBrowserConfig()); // Initialize test data manager this.testDataManager = getTestDataManager(this.envConfig.getEnvironmentName()); await this.testDataManager.initialize(); // Initialize security framework this.securityFramework = new SecurityTestFramework(this.envConfig.getConfig()); await this.securityFramework.initialize(); // Initialize page objects this.dashboardPage = new MasterTrainerDashboard(); this.dashboardPage.setBaseUrl(this.envConfig.getBaseUrl()); console.log(`🚀 Master Trainer E2E Test Suite initialized for ${this.envConfig.getEnvironmentName()}`); } /** * Run the complete master trainer E2E test suite */ async run() { try { await this.testAuthenticationAndAccess(); await this.testDashboardFunctionality(); await this.testEventsManagement(); await this.testTrainerManagement(); await this.testAnnouncementsSystem(); await this.testImportExportFeatures(); await this.testCommunicationTemplates(); await this.testSecurityControls(); console.log('✅ All Master Trainer E2E tests completed successfully'); } catch (error) { console.error('❌ Master Trainer E2E test suite failed:', error.message); throw error; } } /** * Test authentication and access control */ async testAuthenticationAndAccess() { await this.runTestStep('Master Trainer Authentication', async () => { // Test login with master trainer account const masterAccount = this.testDataManager.getTestAccount('masterTrainer'); await this.authManager.login(masterAccount); // Verify successful authentication const isLoggedIn = await this.authManager.isUserLoggedIn(); this.assertTrue(isLoggedIn, 'Master trainer should be logged in'); // Navigate to master trainer dashboard await this.dashboardPage.navigate(); await this.dashboardPage.waitForPageReady(); // Verify dashboard loads correctly const isAuthenticated = await this.dashboardPage.isAuthenticatedAsMasterTrainer(); this.assertTrue(isAuthenticated, 'Should be authenticated as master trainer'); return { authenticated: true, dashboardLoaded: true }; }); await this.runTestStep('Access Control Verification', async () => { // Test access to master trainer specific pages await this.dashboardPage.navigateToEvents(); this.assertUrlMatches('/master-trainer/events/', 'Should access events page'); await this.dashboardPage.navigateToTrainers(); this.assertUrlMatches('/master-trainer/trainers/', 'Should access trainers page'); await this.dashboardPage.navigateToAnnouncements(); this.assertUrlMatches('/master-trainer/announcements/', 'Should access announcements'); return { masterPagesAccessible: true }; }); } /** * Test dashboard functionality */ async testDashboardFunctionality() { await this.runTestStep('Dashboard Navigation', async () => { await this.dashboardPage.navigate(); await this.dashboardPage.waitForDashboardLoaded(); // Test navigation menu const hasNavMenu = await this.dashboardPage.hasNavigationMenu(); this.assertTrue(hasNavMenu, 'Dashboard should have navigation menu'); const menuItems = await this.dashboardPage.getNavigationMenuItems(); this.assertTrue(menuItems.length > 0, 'Navigation menu should have items'); return { navigationWorking: true, menuItems: menuItems.length }; }); await this.runTestStep('Dashboard Statistics', async () => { const stats = await this.dashboardPage.getDashboardStats(); // Verify statistics are present (even if zero) this.assertTrue( stats.totalEvents !== undefined || stats.totalTrainers !== undefined || stats.pendingApprovals !== undefined, 'Dashboard should display statistics' ); return { statisticsLoaded: true, stats }; }); await this.runTestStep('Dashboard Sections Visibility', async () => { const sections = ['events', 'trainers', 'announcements']; const visibleSections = []; for (const section of sections) { const isVisible = await this.dashboardPage.isDashboardSectionVisible(section); if (isVisible) visibleSections.push(section); } this.assertTrue(visibleSections.length > 0, 'At least one dashboard section should be visible'); return { visibleSections }; }); } /** * Test events management functionality */ async testEventsManagement() { await this.runTestStep('Events Overview Access', async () => { await this.dashboardPage.navigateToEvents(); // Wait for events page to load await this.browserManager.waitForPageLoad(); // Verify we're on the events page this.assertUrlMatches('/master-trainer/events/', 'Should be on events overview page'); // Check for events list or empty state const hasEventsTable = await this.hasElement('.events-table, .events-list, .no-events'); this.assertTrue(hasEventsTable, 'Events page should display events table or empty state'); return { eventsPageAccessible: true }; }); await this.runTestStep('Events Management Features', async () => { // Look for common events management features const features = { createEvent: await this.hasElement('a[href*="create"], .create-event, .add-event'), editEvent: await this.hasElement('a[href*="edit"], .edit-event, .event-actions'), eventSearch: await this.hasElement('input[type="search"], .search-events, .events-search'), eventFilters: await this.hasElement('.filter, .events-filter, select') }; const availableFeatures = Object.keys(features).filter(key => features[key]); console.log(` Available features: ${availableFeatures.join(', ')}`); return { eventsFeatures: features, availableFeatures }; }); } /** * Test trainer management functionality */ async testTrainerManagement() { await this.runTestStep('Trainers Overview Access', async () => { await this.dashboardPage.navigateToTrainers(); // Wait for trainers page to load await this.browserManager.waitForPageLoad(); // Verify we're on the trainers page this.assertUrlMatches('/master-trainer/trainers/', 'Should be on trainers management page'); // Check for trainers list const hasTrainersList = await this.hasElement('.trainers-table, .trainers-list, .no-trainers'); this.assertTrue(hasTrainersList, 'Trainers page should display trainers list or empty state'); return { trainersPageAccessible: true }; }); await this.runTestStep('Trainer Management Features', async () => { // Look for trainer management features const features = { addTrainer: await this.hasElement('a[href*="add"], .add-trainer, .create-trainer'), editTrainer: await this.hasElement('a[href*="edit"], .edit-trainer, .trainer-actions'), trainerSearch: await this.hasElement('input[type="search"], .search-trainers'), trainerProfile: await this.hasElement('a[href*="profile"], .trainer-profile, .view-profile') }; const availableFeatures = Object.keys(features).filter(key => features[key]); console.log(` Available trainer features: ${availableFeatures.join(', ')}`); return { trainerFeatures: features, availableFeatures }; }); } /** * Test announcements system */ async testAnnouncementsSystem() { await this.runTestStep('Announcements Access', async () => { await this.dashboardPage.navigateToAnnouncements(); // Wait for announcements page to load await this.browserManager.waitForPageLoad(); // Verify we're on the announcements page this.assertUrlMatches('/master-trainer/announcements/', 'Should be on announcements page'); // Check for announcements interface const hasAnnouncementsInterface = await this.hasElement( '.announcements-list, .announcements-table, .no-announcements, .announcement-item' ); this.assertTrue(hasAnnouncementsInterface, 'Announcements page should display interface'); return { announcementsPageAccessible: true }; }); await this.runTestStep('Announcements Management Features', async () => { const features = { createAnnouncement: await this.hasElement('a[href*="create"], .create-announcement, .add-announcement'), editAnnouncement: await this.hasElement('a[href*="edit"], .edit-announcement, .announcement-actions'), manageAnnouncements: await this.hasElement('a[href*="manage"], .manage-announcements'), announcementSearch: await this.hasElement('input[type="search"], .search-announcements') }; const availableFeatures = Object.keys(features).filter(key => features[key]); console.log(` Available announcement features: ${availableFeatures.join(', ')}`); return { announcementFeatures: features, availableFeatures }; }); } /** * Test import/export features */ async testImportExportFeatures() { await this.runTestStep('Google Sheets Integration Access', async () => { await this.dashboardPage.navigateToGoogleSheets(); // Wait for import/export page to load await this.browserManager.waitForPageLoad(); // Verify we're on the import/export page this.assertUrlMatches('/master-trainer/google-sheets/', 'Should be on Google Sheets page'); // Check for import/export interface const hasImportExportInterface = await this.hasElement( '.import-export, .google-sheets, .data-management, .import-section, .export-section' ); this.assertTrue(hasImportExportInterface, 'Import/Export page should display interface'); return { importExportPageAccessible: true }; }); await this.runTestStep('Import/Export Features', async () => { const features = { importData: await this.hasElement('input[type="file"], .import-button, .upload-file'), exportData: await this.hasElement('.export-button, .download-data, a[href*="export"]'), googleSheets: await this.hasElement('.google-sheets, .sheets-integration'), dataValidation: await this.hasElement('.validate-data, .data-preview') }; const availableFeatures = Object.keys(features).filter(key => features[key]); console.log(` Available import/export features: ${availableFeatures.join(', ')}`); return { importExportFeatures: features, availableFeatures }; }); } /** * Test communication templates */ async testCommunicationTemplates() { await this.runTestStep('Communication Templates Access', async () => { await this.dashboardPage.navigateToCommunicationTemplates(); // Wait for templates page to load await this.browserManager.waitForPageLoad(); // Verify we're on the templates page this.assertUrlMatches('/master-trainer/communication-templates/', 'Should be on communication templates page'); // Check for templates interface const hasTemplatesInterface = await this.hasElement( '.templates-list, .communication-templates, .template-item, .no-templates' ); this.assertTrue(hasTemplatesInterface, 'Templates page should display interface'); return { templatesPageAccessible: true }; }); await this.runTestStep('Template Management Features', async () => { const features = { createTemplate: await this.hasElement('a[href*="create"], .create-template, .add-template'), editTemplate: await this.hasElement('a[href*="edit"], .edit-template, .template-actions'), previewTemplate: await this.hasElement('.preview-template, .template-preview'), templateCategories: await this.hasElement('.template-category, .category-filter') }; const availableFeatures = Object.keys(features).filter(key => features[key]); console.log(` Available template features: ${availableFeatures.join(', ')}`); return { templateFeatures: features, availableFeatures }; }); } /** * Test security controls */ async testSecurityControls() { await this.runTestStep('Authentication Security', async () => { // Test protected URLs redirect properly const protectedUrls = this.testDataManager.getProtectedUrls(); // Logout first await this.authManager.logout(); // Test authentication redirects const authResults = await this.securityFramework.testAuthenticationRedirects( protectedUrls.slice(0, 5) // Test first 5 URLs to save time ); this.assertTrue(authResults.passed > 0, 'Some authentication redirects should work'); // Re-login for next tests const masterAccount = this.testDataManager.getTestAccount('masterTrainer'); await this.authManager.login(masterAccount); return { authRedirectsPassed: authResults.passed, authRedirectsFailed: authResults.failed }; }); await this.runTestStep('Role-Based Access Control', async () => { // Test role-based access scenarios const roleScenarios = this.testDataManager.getRoleAccessTestScenarios(); // Test a subset of scenarios to save time const limitedScenarios = roleScenarios.slice(0, 3); const roleResults = await this.securityFramework.testRoleBasedAccess(limitedScenarios); this.assertTrue(roleResults.passed > 0, 'Some role-based access controls should work'); return { roleAccessPassed: roleResults.passed, roleAccessFailed: roleResults.failed }; }); } /** * Clean up after tests */ async tearDown() { try { // Clean up security framework if (this.securityFramework) { await this.securityFramework.cleanup(); } // Clear test data cache if (this.testDataManager) { this.testDataManager.clearCache(); } // Take final screenshot await this.dashboardPage.takeScreenshot('master-trainer-e2e-final.png'); } catch (error) { console.warn('Cleanup warning:', error.message); } await super.tearDown(); } } /** * Run the master trainer E2E test suite */ async function runMasterTrainerE2ETest() { const test = new MasterTrainerE2ETest(); try { await test.setUp(); await test.run(); } catch (error) { console.error('❌ Master Trainer E2E Test Failed:', error.message); process.exit(1); } finally { await test.tearDown(); } } // Run the test if this file is executed directly if (require.main === module) { runMasterTrainerE2ETest(); } module.exports = { MasterTrainerE2ETest, runMasterTrainerE2ETest };