upskill-event-manager/tests/framework/authentication/AuthManager.js
Ben 7c9ca65cf2
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
feat: add comprehensive test framework and test files
- 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>
2025-08-29 23:23:26 -03:00

431 lines
No EOL
12 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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<void>}
*/
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<void>}
*/
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<void>}
*/
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<void>}
*/
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<void>}
*/
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<void>}
*/
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<void>}
*/
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<void>}
*/
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<boolean>}
*/
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<void>}
*/
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<void>}
*/
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<void>}
*/
async submitLogin() {
await this.clickElement(this.selectors.loginButton);
}
/**
* Check for login errors
* @returns {Promise<string|null>}
*/
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 };