#!/usr/bin/env node /** * CSS Loading Verification Script * Checks that all templates properly load required CSS files */ const puppeteer = require('puppeteer'); const fs = require('fs'); const path = require('path'); // Configuration const CONFIG = { baseUrl: 'https://upskill-staging.measurequick.com', timeout: 30000, viewport: { width: 1920, height: 1080 }, // Pages to test with their expected CSS classes testPages: [ { url: '/master-trainer/dashboard/', name: 'Master Dashboard', requiredCssClasses: [ '.hvac-dashboard-header', '.hvac-stat-card', '.dashboard-section', '.events-table', '.trainers-table' ], requiredStylesheets: [ 'hvac-dashboard', 'hvac-dashboard-enhanced' ] }, { url: '/trainer/dashboard/', name: 'Trainer Dashboard', requiredCssClasses: [ '.hvac-dashboard-header', '.hvac-stat-card', '.hvac-dashboard-stats' ], requiredStylesheets: [ 'hvac-dashboard', 'hvac-dashboard-enhanced' ] }, { url: '/trainer/my-profile/', name: 'Trainer Profile', requiredCssClasses: [ '.hvac-trainer-profile-form', '.profile-section' ], requiredStylesheets: [ 'hvac-dashboard' ] } ] }; // Colors for console output const colors = { red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', reset: '\x1b[0m' }; async function verifyPage(browser, pageConfig) { const page = await browser.newPage(); await page.setViewport(CONFIG.viewport); const results = { name: pageConfig.name, url: pageConfig.url, success: true, issues: [], screenshots: [] }; try { console.log(`\nTesting: ${pageConfig.name} (${pageConfig.url})`); // Navigate to page await page.goto(CONFIG.baseUrl + pageConfig.url, { waitUntil: 'networkidle2', timeout: CONFIG.timeout }); // Check if page loaded (not 404/500) const title = await page.title(); if (title.includes('404') || title.includes('Error')) { results.success = false; results.issues.push(`Page returned error: ${title}`); return results; } // Take screenshot for manual verification const screenshotPath = `test-results/css-verification-${pageConfig.name.toLowerCase().replace(/\s+/g, '-')}.png`; await page.screenshot({ path: screenshotPath, fullPage: true }); results.screenshots.push(screenshotPath); // Check for required stylesheets const stylesheets = await page.evaluate(() => { const links = Array.from(document.querySelectorAll('link[rel="stylesheet"]')); return links.map(link => link.href); }); for (const requiredSheet of pageConfig.requiredStylesheets) { const hasStylesheet = stylesheets.some(href => href.includes(requiredSheet)); if (!hasStylesheet) { results.success = false; results.issues.push(`Missing stylesheet: ${requiredSheet}`); } } // Check for required CSS classes and their computed styles for (const cssClass of pageConfig.requiredCssClasses) { const elementExists = await page.$(cssClass); if (!elementExists) { results.success = false; results.issues.push(`Missing element with class: ${cssClass}`); continue; } // Check if element has meaningful styles (not just browser defaults) const hasStyles = await page.evaluate((selector) => { const element = document.querySelector(selector); if (!element) return false; const styles = window.getComputedStyle(element); // Check for common signs of styling const hasCustomPadding = styles.padding !== '0px'; const hasCustomMargin = styles.margin !== '0px'; const hasCustomBackground = styles.backgroundColor !== 'rgba(0, 0, 0, 0)' && styles.backgroundColor !== 'transparent'; const hasCustomBorder = styles.borderWidth !== '0px'; const hasCustomFont = styles.fontSize !== '16px' || styles.fontWeight !== '400'; return hasCustomPadding || hasCustomMargin || hasCustomBackground || hasCustomBorder || hasCustomFont; }, cssClass); if (!hasStyles) { results.success = false; results.issues.push(`Element ${cssClass} exists but appears unstyled`); } } // Check for WordPress wp_head output (indicates get_header() was called) const hasWpHead = await page.evaluate(() => { // Look for typical wp_head() output const hasWpMeta = document.querySelector('meta[name="generator"][content*="WordPress"]'); const hasWpScripts = document.querySelector('script[src*="wp-includes"]'); const hasWpStyles = document.querySelector('link[href*="wp-includes"]'); return !!(hasWpMeta || hasWpScripts || hasWpStyles); }); if (!hasWpHead) { results.success = false; results.issues.push('No WordPress wp_head() output detected - likely missing get_header()'); } console.log(` ${results.success ? colors.green + '✅ PASSED' : colors.red + '❌ FAILED'}${colors.reset}`); if (!results.success) { results.issues.forEach(issue => { console.log(` ${colors.red}→ ${issue}${colors.reset}`); }); } } catch (error) { results.success = false; results.issues.push(`Page load error: ${error.message}`); console.log(` ${colors.red}❌ ERROR: ${error.message}${colors.reset}`); } finally { await page.close(); } return results; } async function main() { console.log(`${colors.blue}=== CSS Loading Verification ===${colors.reset}`); console.log(`Testing: ${CONFIG.baseUrl}`); // Ensure test results directory exists if (!fs.existsSync('test-results')) { fs.mkdirSync('test-results', { recursive: true }); } const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const results = []; let totalTests = 0; let passedTests = 0; try { for (const pageConfig of CONFIG.testPages) { const result = await verifyPage(browser, pageConfig); results.push(result); totalTests++; if (result.success) passedTests++; } // Summary console.log(`\n${colors.blue}=== Verification Summary ===${colors.reset}`); console.log(`Total pages tested: ${totalTests}`); console.log(`${colors.green}Passed: ${passedTests}${colors.reset}`); console.log(`${colors.red}Failed: ${totalTests - passedTests}${colors.reset}`); if (passedTests === totalTests) { console.log(`\n${colors.green}🎉 ALL CSS LOADING TESTS PASSED!${colors.reset}`); } else { console.log(`\n${colors.red}🚨 CSS LOADING ISSUES DETECTED!${colors.reset}`); console.log('Check screenshots in test-results/ directory for visual verification.'); } // Save detailed results fs.writeFileSync('test-results/css-verification-results.json', JSON.stringify(results, null, 2)); } finally { await browser.close(); } process.exit(passedTests === totalTests ? 0 : 1); } // Run if called directly if (require.main === module) { main().catch(console.error); } module.exports = { verifyPage, CONFIG };