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>
293 lines
No EOL
8.9 KiB
JavaScript
293 lines
No EOL
8.9 KiB
JavaScript
/**
|
|
* Authentication Fixtures for Playwright Tests
|
|
*
|
|
* Provides reusable authentication fixtures with state management:
|
|
* - Automatic authentication setup
|
|
* - State persistence across tests
|
|
* - Role-based test isolation
|
|
* - Performance optimization
|
|
* - Error handling
|
|
*
|
|
* @package HVAC_Community_Events
|
|
* @version 3.0.0
|
|
* @created 2025-08-20
|
|
*/
|
|
|
|
const { test: base, expect } = require('@playwright/test');
|
|
const LoginPage = require('./LoginPage');
|
|
const {
|
|
getAuthStatePath,
|
|
saveAuthState,
|
|
clearAuthState,
|
|
verifyAuthentication,
|
|
getUserConfig
|
|
} = require('./auth.setup');
|
|
|
|
/**
|
|
* Extended test with authentication fixtures
|
|
*/
|
|
const test = base.extend({
|
|
/**
|
|
* Authenticated trainer page
|
|
*/
|
|
authenticatedTrainerPage: async ({ browser }, use) => {
|
|
const context = await browser.newContext();
|
|
const page = await context.newPage();
|
|
const loginPage = new LoginPage(page);
|
|
|
|
try {
|
|
await loginPage.loginWithStateManagement('trainer', context);
|
|
await use(page);
|
|
} finally {
|
|
await context.close();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Authenticated master trainer page
|
|
*/
|
|
authenticatedMasterTrainerPage: async ({ browser }, use) => {
|
|
const context = await browser.newContext();
|
|
const page = await context.newPage();
|
|
const loginPage = new LoginPage(page);
|
|
|
|
try {
|
|
await loginPage.loginWithStateManagement('master_trainer', context);
|
|
await use(page);
|
|
} finally {
|
|
await context.close();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Authenticated admin page
|
|
*/
|
|
authenticatedAdminPage: async ({ browser }, use) => {
|
|
const context = await browser.newContext();
|
|
const page = await context.newPage();
|
|
const loginPage = new LoginPage(page);
|
|
|
|
try {
|
|
await loginPage.loginWithStateManagement('admin', context);
|
|
await use(page);
|
|
} finally {
|
|
await context.close();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Login page helper
|
|
*/
|
|
loginPage: async ({ page }, use) => {
|
|
const loginPage = new LoginPage(page);
|
|
await use(loginPage);
|
|
},
|
|
|
|
/**
|
|
* Multi-role context for testing role switching
|
|
*/
|
|
multiRoleContext: async ({ browser }, use) => {
|
|
const contexts = {};
|
|
const pages = {};
|
|
|
|
try {
|
|
// Create contexts for each role
|
|
for (const userType of ['trainer', 'master_trainer', 'admin']) {
|
|
contexts[userType] = await browser.newContext();
|
|
pages[userType] = await contexts[userType].newPage();
|
|
const loginPage = new LoginPage(pages[userType]);
|
|
await loginPage.loginWithStateManagement(userType, contexts[userType]);
|
|
}
|
|
|
|
await use({ contexts, pages });
|
|
} finally {
|
|
// Clean up all contexts
|
|
for (const context of Object.values(contexts)) {
|
|
await context.close();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Authentication test helpers
|
|
*/
|
|
const authHelpers = {
|
|
/**
|
|
* Login to page as specific user type
|
|
* @param {Page} page - Playwright page
|
|
* @param {string} userType - User type
|
|
* @param {Object} options - Login options
|
|
*/
|
|
async loginAs(page, userType, options = {}) {
|
|
const loginPage = new LoginPage(page);
|
|
await loginPage.login(userType, options);
|
|
},
|
|
|
|
/**
|
|
* Verify user authentication and role
|
|
* @param {Page} page - Playwright page
|
|
* @param {string} expectedUserType - Expected user type
|
|
*/
|
|
async verifyAuth(page, expectedUserType) {
|
|
await verifyAuthentication(page, expectedUserType);
|
|
},
|
|
|
|
/**
|
|
* Setup authentication for test suite
|
|
* @param {string} userType - Default user type for suite
|
|
*/
|
|
setupAuth(userType = 'trainer') {
|
|
return {
|
|
beforeEach: async ({ page }) => {
|
|
await authHelpers.loginAs(page, userType);
|
|
},
|
|
afterEach: async ({ page }) => {
|
|
// Optional: logout after each test
|
|
if (process.env.LOGOUT_AFTER_TEST) {
|
|
const loginPage = new LoginPage(page);
|
|
await loginPage.logout();
|
|
}
|
|
}
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Create authentication test context with state management
|
|
* @param {Browser} browser - Playwright browser
|
|
* @param {string} userType - User type
|
|
* @returns {Object} Context and page with authentication
|
|
*/
|
|
async createAuthContext(browser, userType) {
|
|
// Try to use saved authentication state
|
|
const authStatePath = await getAuthStatePath(userType);
|
|
let context;
|
|
|
|
if (authStatePath) {
|
|
try {
|
|
context = await browser.newContext({ storageState: authStatePath });
|
|
const page = await context.newPage();
|
|
|
|
// Verify saved state is still valid
|
|
await verifyAuthentication(page, userType);
|
|
console.log(`✅ Using saved auth state for ${userType}`);
|
|
|
|
return { context, page };
|
|
} catch (error) {
|
|
console.log(`⚠️ Saved auth state invalid for ${userType}, creating fresh context`);
|
|
await context?.close();
|
|
}
|
|
}
|
|
|
|
// Create fresh context and login
|
|
context = await browser.newContext();
|
|
const page = await context.newPage();
|
|
const loginPage = new LoginPage(page);
|
|
|
|
await loginPage.login(userType);
|
|
await saveAuthState(userType, context);
|
|
|
|
return { context, page };
|
|
},
|
|
|
|
/**
|
|
* Clear all authentication states (for test cleanup)
|
|
*/
|
|
async clearAllAuthStates() {
|
|
await clearAuthState();
|
|
},
|
|
|
|
/**
|
|
* Get user configuration for testing
|
|
* @param {string} userType - User type
|
|
* @returns {Object} User configuration
|
|
*/
|
|
getUserConfig(userType) {
|
|
return getUserConfig(userType);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Authentication test scenarios
|
|
*/
|
|
const authScenarios = {
|
|
/**
|
|
* Test authentication for all user types
|
|
* @param {Function} testFn - Test function to run for each user type
|
|
*/
|
|
forAllUserTypes(testFn) {
|
|
const userTypes = ['trainer', 'master_trainer', 'admin'];
|
|
|
|
for (const userType of userTypes) {
|
|
test(`${userType} authentication`, async ({ browser }) => {
|
|
const { context, page } = await authHelpers.createAuthContext(browser, userType);
|
|
|
|
try {
|
|
await testFn(page, userType);
|
|
} finally {
|
|
await context.close();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Test role-based access control
|
|
* @param {Object} roleTests - Map of userType to test function
|
|
*/
|
|
forRoleAccess(roleTests) {
|
|
for (const [userType, testFn] of Object.entries(roleTests)) {
|
|
test(`${userType} role access`, async ({ browser }) => {
|
|
const { context, page } = await authHelpers.createAuthContext(browser, userType);
|
|
|
|
try {
|
|
await testFn(page, userType);
|
|
} finally {
|
|
await context.close();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Test unauthorized access (should be blocked)
|
|
* @param {string} authorizedUserType - User type that should have access
|
|
* @param {string[]} unauthorizedUserTypes - User types that should NOT have access
|
|
* @param {Function} testFn - Test function that should fail for unauthorized users
|
|
*/
|
|
testUnauthorizedAccess(authorizedUserType, unauthorizedUserTypes, testFn) {
|
|
// Test authorized access
|
|
test(`${authorizedUserType} authorized access`, async ({ browser }) => {
|
|
const { context, page } = await authHelpers.createAuthContext(browser, authorizedUserType);
|
|
|
|
try {
|
|
await testFn(page, authorizedUserType, true); // Should succeed
|
|
} finally {
|
|
await context.close();
|
|
}
|
|
});
|
|
|
|
// Test unauthorized access
|
|
for (const userType of unauthorizedUserTypes) {
|
|
test(`${userType} unauthorized access blocked`, async ({ browser }) => {
|
|
const { context, page } = await authHelpers.createAuthContext(browser, userType);
|
|
|
|
try {
|
|
await expect(async () => {
|
|
await testFn(page, userType, false); // Should fail
|
|
}).rejects.toThrow();
|
|
} finally {
|
|
await context.close();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
module.exports = {
|
|
test,
|
|
expect,
|
|
authHelpers,
|
|
authScenarios,
|
|
LoginPage
|
|
}; |