/** * 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 };