/** * HVAC Community Events - CSS Asset Loading Comprehensive Test Suite * * Tests for community-login.css and community-login-enhanced.css loading, * application, and functionality across different browser contexts. * * CRITICAL ISSUES TESTED: * 1. Missing hvac-login.css file (referenced but doesn't exist) * 2. community-login.css and community-login-enhanced.css not being enqueued * 3. Template fallback to inline styles * 4. Responsive design and accessibility features * 5. Browser-specific compatibility issues * * @package HVAC_Community_Events * @since 2.0.0 */ const { test, expect } = require('@playwright/test'); const fs = require('fs').promises; const path = require('path'); // Test configuration const CSS_TEST_CONFIG = { BASE_URL: process.env.BASE_URL || 'http://localhost:8080', CSS_FILES: { BASE: path.resolve(__dirname, '../assets/css/community-login.css'), ENHANCED: path.resolve(__dirname, '../assets/css/community-login-enhanced.css'), MISSING: path.resolve(__dirname, '../assets/css/hvac-login.css') }, LOGIN_PAGES: [ '/community-login/', '/training-login/', '/trainer/login/' ], RESPONSIVE_BREAKPOINTS: [ { width: 1920, height: 1080, name: 'desktop' }, { width: 768, height: 1024, name: 'tablet' }, { width: 375, height: 667, name: 'mobile' } ] }; /** * CSS Asset Testing Framework */ class CSSAssetTestFramework { constructor(page) { this.page = page; this.cssErrors = []; this.loadedStyles = []; this.networkRequests = []; } /** * Enable CSS monitoring */ async enableCSSMonitoring() { // Monitor failed CSS requests this.page.on('requestfailed', (request) => { if (request.url().includes('.css')) { this.cssErrors.push({ url: request.url(), failure: request.failure(), timestamp: new Date().toISOString() }); } }); // Monitor successful CSS loads this.page.on('response', async (response) => { if (response.url().includes('.css') && response.status() === 200) { this.loadedStyles.push({ url: response.url(), size: parseInt(response.headers()['content-length'] || '0'), timestamp: new Date().toISOString() }); } }); // Monitor all network requests this.page.on('request', (request) => { this.networkRequests.push({ url: request.url(), resourceType: request.resourceType(), method: request.method() }); }); } /** * Check if CSS styles are applied to elements */ async verifyCSSApplication(selector, expectedStyles) { const element = await this.page.locator(selector).first(); for (const [property, expectedValue] of Object.entries(expectedStyles)) { const actualValue = await element.evaluate((el, prop) => { return window.getComputedStyle(el).getPropertyValue(prop); }, property); if (actualValue !== expectedValue) { throw new Error(`CSS property ${property} on ${selector}: expected "${expectedValue}", got "${actualValue}"`); } } } /** * Get CSS loading report */ getCSSLoadingReport() { return { errors: this.cssErrors, loaded: this.loadedStyles, totalRequests: this.networkRequests.length, cssRequests: this.networkRequests.filter(r => r.url.includes('.css')).length }; } } // ============================================================================== // CSS FILE EXISTENCE AND CONTENT VALIDATION TESTS // ============================================================================== test.describe('CSS File Existence and Content Validation', () => { test('community-login.css file exists and has valid content', async () => { console.log('๐Ÿ” Testing community-login.css file existence and content...'); // Check if base CSS file exists const baseCSS = await fs.access(CSS_TEST_CONFIG.CSS_FILES.BASE).then(() => true).catch(() => false); expect(baseCSS).toBe(true); // Read and validate content const baseCSSContent = await fs.readFile(CSS_TEST_CONFIG.CSS_FILES.BASE, 'utf-8'); // Verify file has content expect(baseCSSContent.length).toBeGreaterThan(0); // Check for essential CSS selectors const requiredSelectors = [ '.hvac-community-login-wrapper', '.hvac-login-form-card', '.hvac-login-form-input', '.hvac-login-submit', '.hvac-password-toggle' ]; for (const selector of requiredSelectors) { expect(baseCSSContent).toContain(selector); } // Verify responsive design breakpoints expect(baseCSSContent).toContain('@media (max-width: 768px)'); expect(baseCSSContent).toContain('@media (max-width: 480px)'); // Verify accessibility support expect(baseCSSContent).toContain('@media (prefers-reduced-motion: reduce)'); expect(baseCSSContent).toContain('@media (prefers-contrast: high)'); console.log('โœ… Base CSS file validation passed'); }); test('community-login-enhanced.css file exists and has enhancement features', async () => { console.log('๐Ÿ” Testing community-login-enhanced.css file existence and features...'); // Check if enhanced CSS file exists const enhancedCSS = await fs.access(CSS_TEST_CONFIG.CSS_FILES.ENHANCED).then(() => true).catch(() => false); expect(enhancedCSS).toBe(true); // Read and validate content const enhancedCSSContent = await fs.readFile(CSS_TEST_CONFIG.CSS_FILES.ENHANCED, 'utf-8'); // Verify file has content expect(enhancedCSSContent.length).toBeGreaterThan(0); // Check for enhancement features const requiredEnhancements = [ '.hvac-login-form-card:hover', '@keyframes hvac-fade-in-up', '.hvac-login-submit::before', '@media (prefers-color-scheme: dark)', 'animation: hvac-fade-in-up' ]; for (const feature of requiredEnhancements) { expect(enhancedCSSContent).toContain(feature); } // Verify dark mode support expect(enhancedCSSContent).toContain('background-color: #1a1a1a'); expect(enhancedCSSContent).toContain('color: #e0e0e0'); console.log('โœ… Enhanced CSS file validation passed'); }); test('CRITICAL: hvac-login.css file does NOT exist (system tries to load this)', async () => { console.log('๐Ÿšจ CRITICAL: Testing missing hvac-login.css file issue...'); // Verify the file that's being enqueued doesn't exist const missingCSS = await fs.access(CSS_TEST_CONFIG.CSS_FILES.MISSING).then(() => true).catch(() => false); expect(missingCSS).toBe(false); console.log('โŒ Confirmed: hvac-login.css does not exist but is referenced in enqueue_login_assets()'); console.log('๐Ÿ”ง RECOMMENDATION: Update HVAC_Scripts_Styles::enqueue_login_assets() to use community-login.css'); }); test('CSS file sizes are within performance limits', async () => { console.log('๐Ÿ” Testing CSS file sizes for performance...'); const baseStat = await fs.stat(CSS_TEST_CONFIG.CSS_FILES.BASE); const enhancedStat = await fs.stat(CSS_TEST_CONFIG.CSS_FILES.ENHANCED); const maxBaseSize = 50 * 1024; // 50KB const maxEnhancedSize = 100 * 1024; // 100KB expect(baseStat.size).toBeLessThan(maxBaseSize); expect(enhancedStat.size).toBeLessThan(maxEnhancedSize); console.log(`๐Ÿ“Š Base CSS: ${Math.round(baseStat.size / 1024)}KB (limit: ${Math.round(maxBaseSize / 1024)}KB)`); console.log(`๐Ÿ“Š Enhanced CSS: ${Math.round(enhancedStat.size / 1024)}KB (limit: ${Math.round(maxEnhancedSize / 1024)}KB)`); }); }); // ============================================================================== // CSS LOADING AND APPLICATION TESTS // ============================================================================== test.describe('CSS Loading and Application Tests', () => { test('Login page loads with inline CSS fallback (current system)', async ({ page }) => { console.log('๐Ÿ” Testing login page CSS loading with current system...'); const cssFramework = new CSSAssetTestFramework(page); await cssFramework.enableCSSMonitoring(); // Navigate to login page await page.goto(`${CSS_TEST_CONFIG.BASE_URL}/community-login/`); await page.waitForLoadState('networkidle'); // Check if inline styles are present (current fallback mechanism) const inlineStyles = await page.evaluate(() => { const styles = Array.from(document.querySelectorAll('style')); return styles.map(style => style.textContent).join('\n'); }); // Verify template inline styles are present expect(inlineStyles).toContain('.hvac-community-login-wrapper'); expect(inlineStyles).toContain('max-width: none !important'); expect(inlineStyles).toContain('background: linear-gradient'); // Check CSS loading report const report = cssFramework.getCSSLoadingReport(); console.log('๐Ÿ“Š CSS Loading Report:', report); // Verify missing hvac-login.css causes 404 const hvacLoginCSS404 = report.errors.find(error => error.url.includes('hvac-login.css')); if (hvacLoginCSS404) { console.log('โŒ Confirmed: hvac-login.css returns 404 as expected'); } console.log('โœ… Login page loads with inline CSS fallback'); }); test('Login form elements have proper styling (via inline CSS)', async ({ page }) => { console.log('๐Ÿ” Testing login form element styling...'); const cssFramework = new CSSAssetTestFramework(page); await cssFramework.enableCSSMonitoring(); await page.goto(`${CSS_TEST_CONFIG.BASE_URL}/community-login/`); await page.waitForLoadState('domcontentloaded'); // Wait for login form to render await page.waitForSelector('.hvac-login-form-card, .hvac-login-fallback, .hvac-emergency-login', { timeout: 10000 }); // Test if login form elements are styled (either via inline CSS or class presence) const loginWrapper = page.locator('.hvac-community-login-wrapper, .hvac-login-fallback, .hvac-emergency-login'); await expect(loginWrapper).toBeVisible(); // Check if form inputs are present and functional const usernameInput = page.locator('input[name="log"], input[name="user_login"], #user_login'); const passwordInput = page.locator('input[name="pwd"], input[name="user_pass"], #user_pass'); const submitButton = page.locator('input[type="submit"], button[type="submit"]'); await expect(usernameInput).toBeVisible(); await expect(passwordInput).toBeVisible(); await expect(submitButton).toBeVisible(); console.log('โœ… Login form elements are properly styled and functional'); }); }); // ============================================================================== // RESPONSIVE DESIGN AND BROWSER COMPATIBILITY TESTS // ============================================================================== test.describe('Responsive Design and Browser Compatibility', () => { test('Login page responsive design across breakpoints', async ({ page, browserName }) => { console.log(`๐Ÿ” Testing responsive design on ${browserName}...`); for (const breakpoint of CSS_TEST_CONFIG.RESPONSIVE_BREAKPOINTS) { console.log(`๐Ÿ“ฑ Testing ${breakpoint.name} (${breakpoint.width}x${breakpoint.height})`); await page.setViewportSize({ width: breakpoint.width, height: breakpoint.height }); await page.goto(`${CSS_TEST_CONFIG.BASE_URL}/community-login/`); await page.waitForLoadState('domcontentloaded'); // Wait for form to render await page.waitForSelector('.hvac-community-login-wrapper, .hvac-login-fallback, .hvac-emergency-login', { timeout: 5000 }); // Take screenshot for visual validation await page.screenshot({ path: `./test-screenshots/login-${browserName}-${breakpoint.name}.png`, fullPage: true }); // Verify layout doesn't break at different screen sizes const formContainer = page.locator('.hvac-login-form-card, .hvac-login-fallback, .hvac-emergency-login'); await expect(formContainer).toBeVisible(); // Check that form elements remain accessible const inputElements = page.locator('input[type="text"], input[type="password"], input[type="email"]'); const inputCount = await inputElements.count(); expect(inputCount).toBeGreaterThan(0); console.log(`โœ… ${breakpoint.name} layout validated`); } }); test('Safari browser compatibility', async ({ page, browserName }) => { if (browserName !== 'webkit') { test.skip('Skipping Safari-specific test on non-Safari browser'); } console.log('๐Ÿ” Testing Safari browser compatibility...'); const cssFramework = new CSSAssetTestFramework(page); await cssFramework.enableCSSMonitoring(); await page.goto(`${CSS_TEST_CONFIG.BASE_URL}/community-login/`); await page.waitForLoadState('networkidle'); // Verify Safari can render login form properly const loginForm = page.locator('form, .hvac-login-form, .hvac-login-fallback'); await expect(loginForm).toBeVisible(); // Check CSS loading report for Safari-specific issues const report = cssFramework.getCSSLoadingReport(); console.log('๐ŸŽ Safari CSS Loading Report:', report); // Safari should still function even with CSS loading issues const submitButton = page.locator('input[type="submit"], button[type="submit"]'); await expect(submitButton).toBeVisible(); console.log('โœ… Safari browser compatibility validated'); }); }); // ============================================================================== // ACCESSIBILITY AND USER EXPERIENCE TESTS // ============================================================================== test.describe('Accessibility and User Experience Tests', () => { test('Reduced motion preference support', async ({ page }) => { console.log('๐Ÿ” Testing reduced motion preference support...'); // Emulate reduced motion preference await page.emulateMedia({ reducedMotion: 'reduce' }); await page.goto(`${CSS_TEST_CONFIG.BASE_URL}/community-login/`); await page.waitForLoadState('domcontentloaded'); // Take screenshot for visual validation await page.screenshot({ path: './test-screenshots/login-reduced-motion.png', fullPage: true }); // Verify page still loads and functions without animations const loginForm = page.locator('form, .hvac-login-form-card, .hvac-login-fallback'); await expect(loginForm).toBeVisible(); console.log('โœ… Reduced motion preference support validated'); }); test('High contrast mode support', async ({ page }) => { console.log('๐Ÿ” Testing high contrast mode support...'); // Emulate high contrast preference await page.emulateMedia({ forcedColors: 'active' }); await page.goto(`${CSS_TEST_CONFIG.BASE_URL}/community-login/`); await page.waitForLoadState('domcontentloaded'); // Take screenshot for visual validation await page.screenshot({ path: './test-screenshots/login-high-contrast.png', fullPage: true }); // Verify form elements remain accessible in high contrast const inputElements = page.locator('input[type="text"], input[type="password"], input[type="email"]'); const inputCount = await inputElements.count(); expect(inputCount).toBeGreaterThan(0); console.log('โœ… High contrast mode support validated'); }); test('Dark mode CSS application (if enhanced CSS were loaded)', async ({ page }) => { console.log('๐Ÿ” Testing dark mode CSS support...'); // Emulate dark color scheme await page.emulateMedia({ colorScheme: 'dark' }); await page.goto(`${CSS_TEST_CONFIG.BASE_URL}/community-login/`); await page.waitForLoadState('domcontentloaded'); // Take screenshot for visual validation await page.screenshot({ path: './test-screenshots/login-dark-mode.png', fullPage: true }); // Note: Current system doesn't load enhanced CSS, so dark mode won't apply // This test validates that the page still functions const loginForm = page.locator('form, .hvac-login-form-card, .hvac-login-fallback'); await expect(loginForm).toBeVisible(); console.log('โš ๏ธ Dark mode tested (enhanced CSS not loaded in current system)'); }); test('Focus management and keyboard navigation', async ({ page }) => { console.log('๐Ÿ” Testing keyboard navigation and focus management...'); await page.goto(`${CSS_TEST_CONFIG.BASE_URL}/community-login/`); await page.waitForLoadState('domcontentloaded'); // Test tab navigation through form elements await page.keyboard.press('Tab'); // Check if focus is visible and properly managed const focusedElement = await page.evaluate(() => document.activeElement?.tagName); console.log('๐Ÿ“ฑ First tab focus:', focusedElement); // Continue tabbing through form await page.keyboard.press('Tab'); await page.keyboard.press('Tab'); // Verify submit button can be reached via keyboard const submitButton = page.locator('input[type="submit"], button[type="submit"]'); await expect(submitButton).toBeVisible(); console.log('โœ… Keyboard navigation validated'); }); }); // ============================================================================== // PERFORMANCE AND SECURITY TESTS // ============================================================================== test.describe('Performance and Security Tests', () => { test('CSS loading performance monitoring', async ({ page }) => { console.log('๐Ÿ” Testing CSS loading performance...'); const cssFramework = new CSSAssetTestFramework(page); await cssFramework.enableCSSMonitoring(); const startTime = Date.now(); await page.goto(`${CSS_TEST_CONFIG.BASE_URL}/community-login/`); await page.waitForLoadState('networkidle'); const loadTime = Date.now() - startTime; console.log(`โฑ๏ธ Total page load time: ${loadTime}ms`); // Verify page loads within acceptable time expect(loadTime).toBeLessThan(5000); // 5 seconds max const report = cssFramework.getCSSLoadingReport(); console.log('๐Ÿ“Š Performance Report:', { totalLoadTime: loadTime, cssRequests: report.cssRequests, cssErrors: report.errors.length, loadedStyles: report.loaded.length }); console.log('โœ… Performance monitoring completed'); }); test('CSS content security validation', async ({ page }) => { console.log('๐Ÿ” Testing CSS content security...'); await page.goto(`${CSS_TEST_CONFIG.BASE_URL}/community-login/`); await page.waitForLoadState('domcontentloaded'); // Check for potential XSS in inline styles const inlineStyles = await page.evaluate(() => { const styles = Array.from(document.querySelectorAll('style')); return styles.map(style => style.textContent).join('\n'); }); // Verify no script injection in CSS expect(inlineStyles).not.toContain('