/** * Authentication Manager - Centralized authentication handling * Manages all user login/logout scenarios and role-based authentication */ const { getBrowserManager } = require('../browser/BrowserManager'); const BasePage = require('../base/BasePage'); class AuthManager { constructor() { this.currentUser = null; this.isLoggedIn = false; this.browserManager = null; this.loginPage = null; this.config = null; } /** * Initialize authentication manager * @param {Object} config - Configuration object * @returns {Promise} */ async initialize(config = {}) { this.config = { baseUrl: 'https://upskill-staging.measurequick.com', loginPath: '/community-login/', logoutPath: '/wp-login.php?action=logout', ...config }; this.browserManager = getBrowserManager(); this.loginPage = new LoginPage(); } /** * Login with user credentials * @param {Object} user - User credentials * @param {Object} options - Login options * @returns {Promise} */ async login(user, options = {}) { const loginOptions = { verifySuccess: true, takeScreenshot: false, ...options }; console.log(`🔐 Logging in as ${user.username} (${user.role || 'unknown role'})`); try { // Navigate to login page await this.loginPage.navigate(); // Fill login form await this.loginPage.fillLoginForm(user.username, user.password); // Submit form await this.loginPage.submitLogin(); // Wait for redirect and verify login success if (loginOptions.verifySuccess) { await this.verifyLoginSuccess(user); } this.currentUser = user; this.isLoggedIn = true; if (loginOptions.takeScreenshot) { await this.browserManager.takeScreenshot(`login-success-${user.username}.png`); } console.log(` ✅ Successfully logged in as ${user.username}`); } catch (error) { console.error(` ❌ Login failed for ${user.username}: ${error.message}`); throw error; } } /** * Logout current user * @param {Object} options - Logout options * @returns {Promise} */ async logout(options = {}) { const logoutOptions = { verifySuccess: true, ...options }; if (!this.isLoggedIn) { console.log(' â„šī¸ No user logged in'); return; } console.log(`🔓 Logging out ${this.currentUser?.username || 'current user'}`); try { const page = this.browserManager.getCurrentPage(); // Try to find and click logout link const logoutSelectors = [ 'a[href*="wp-login.php?action=logout"]', 'a[href*="logout"]', '.logout-link', '#wp-admin-bar-logout a' ]; let loggedOut = false; for (const selector of logoutSelectors) { try { await page.waitForSelector(selector, { timeout: 5000 }); await page.click(selector); loggedOut = true; break; } catch (error) { // Try next selector continue; } } // Fallback: navigate to logout URL directly if (!loggedOut) { const logoutUrl = this.config.baseUrl + this.config.logoutPath; await page.goto(logoutUrl); } // Wait for logout confirmation if (logoutOptions.verifySuccess) { await this.verifyLogoutSuccess(); } this.currentUser = null; this.isLoggedIn = false; console.log(' ✅ Successfully logged out'); } catch (error) { console.error(` ❌ Logout failed: ${error.message}`); this.currentUser = null; this.isLoggedIn = false; } } /** * Quick login for master trainer role * @param {Object} options - Login options * @returns {Promise} */ async loginAsMasterTrainer(options = {}) { const masterUser = this.getMasterTrainerAccount(); await this.login(masterUser, options); } /** * Quick login for regular trainer role * @param {Object} options - Login options * @returns {Promise} */ async loginAsTrainer(options = {}) { const trainerUser = this.getTrainerAccount(); await this.login(trainerUser, options); } /** * Verify that login was successful * @param {Object} user - User that attempted login * @returns {Promise} */ async verifyLoginSuccess(user) { const page = this.browserManager.getCurrentPage(); // Wait for redirect away from login page try { await page.waitForURL(url => !url.includes('community-login'), { timeout: 15000 }); } catch (error) { throw new Error('Login failed - still on login page'); } // Look for logged-in indicators const loggedInSelectors = [ 'body.logged-in', '#wpadminbar', '.dashboard-navigation', '[data-user-role]' ]; let loginConfirmed = false; for (const selector of loggedInSelectors) { try { await page.waitForSelector(selector, { timeout: 10000 }); loginConfirmed = true; break; } catch (error) { continue; } } if (!loginConfirmed) { throw new Error('Login success could not be verified'); } // Verify user role if specified if (user.role) { await this.verifyUserRole(user.role); } } /** * Verify that logout was successful * @returns {Promise} */ async verifyLogoutSuccess() { const page = this.browserManager.getCurrentPage(); try { // Wait for logout indicators await Promise.race([ page.waitForURL(url => url.includes('community-login')), page.waitForURL(url => url.includes('wp-login')), page.waitForSelector('body:not(.logged-in)', { timeout: 10000 }) ]); } catch (error) { throw new Error('Logout success could not be verified'); } } /** * Verify user has expected role * @param {string} expectedRole - Expected user role * @returns {Promise} */ async verifyUserRole(expectedRole) { const page = this.browserManager.getCurrentPage(); try { // Check for role-specific elements or attributes const roleSelectors = { 'master_trainer': [ '[data-user-role*="master"]', '.master-trainer-dashboard', 'a[href*="master-trainer"]' ], 'hvac_trainer': [ '[data-user-role*="trainer"]', '.trainer-dashboard', 'a[href*="trainer/dashboard"]' ] }; const selectors = roleSelectors[expectedRole] || []; let roleConfirmed = false; for (const selector of selectors) { try { await page.waitForSelector(selector, { timeout: 5000 }); roleConfirmed = true; break; } catch (error) { continue; } } if (!roleConfirmed) { console.warn(`Could not verify user role: ${expectedRole}`); } } catch (error) { console.warn(`Role verification failed: ${error.message}`); } } /** * Check if user is currently logged in * @returns {Promise} */ async isUserLoggedIn() { try { const page = this.browserManager.getCurrentPage(); const loggedIn = await page.$('body.logged-in, #wpadminbar') !== null; this.isLoggedIn = loggedIn; return loggedIn; } catch (error) { return false; } } /** * Get current user information * @returns {Object|null} */ getCurrentUser() { return this.currentUser; } /** * Get master trainer account credentials * @returns {Object} */ getMasterTrainerAccount() { return { username: 'test_master', password: 'TestMaster123!', email: 'test_master@example.com', role: 'master_trainer' }; } /** * Get alternative master trainer account * @returns {Object} */ getAlternateMasterTrainerAccount() { return { username: 'JoeMedosch@gmail.com', password: 'JoeTrainer2025@', email: 'JoeMedosch@gmail.com', role: 'master_trainer' }; } /** * Get regular trainer account credentials * @returns {Object} */ getTrainerAccount() { return { username: 'test_trainer', password: 'TestTrainer123!', email: 'test_trainer@example.com', role: 'hvac_trainer' }; } /** * Clean up authentication state * @returns {Promise} */ async cleanup() { if (this.isLoggedIn) { await this.logout({ verifySuccess: false }); } this.currentUser = null; this.isLoggedIn = false; } } /** * Login Page Object - Handles login page interactions */ class LoginPage extends BasePage { constructor() { super(); this.url = ''; this.selectors = { usernameField: '#user_login, [name="log"], input[type="text"]', passwordField: '#user_pass, [name="pwd"], input[type="password"]', loginButton: '#wp-submit, [name="wp-submit"], input[type="submit"], button[type="submit"]', loginForm: '#loginform, .login-form, form[name="loginform"]', errorMessage: '.login_error, .error, .notice-error' }; } /** * Set login page URL based on environment * @param {string} baseUrl - Base URL * @param {string} loginPath - Login path */ setLoginUrl(baseUrl, loginPath) { this.url = baseUrl + loginPath; } /** * Fill login form with credentials * @param {string} username - Username * @param {string} password - Password * @returns {Promise} */ async fillLoginForm(username, password) { await this.waitForElement(this.selectors.usernameField); await this.fillField(this.selectors.usernameField, username); await this.fillField(this.selectors.passwordField, password); } /** * Submit login form * @returns {Promise} */ async submitLogin() { await this.clickElement(this.selectors.loginButton); } /** * Check for login errors * @returns {Promise} */ async getLoginError() { try { const errorElement = await this.page.$(this.selectors.errorMessage); if (errorElement) { return await errorElement.textContent(); } } catch (error) { // No error message found } return null; } /** * Set base URL for navigation * @param {string} baseUrl - Base URL */ setBaseUrl(baseUrl) { this.url = baseUrl + '/community-login/'; } } // Singleton instance let authManager = null; /** * Get singleton AuthManager instance * @returns {AuthManager} */ function getAuthManager() { if (!authManager) { authManager = new AuthManager(); } return authManager; } module.exports = { AuthManager, getAuthManager, LoginPage };