#!/usr/bin/env bun /** * HOVER SYNCHRONIZATION TEST * =========================== * Tests hover state synchronization between action bar and hamburger menu buttons * * CRITICAL BUG: PDF/Print button hover states don't sync between locations * * Expected behavior: * - Hovering action bar PDF button should highlight menu PDF button * - Hovering action bar Print button should highlight menu Print button * - Hovering menu buttons should highlight action bar buttons * - Classes added: .pdf-hover-sync and .print-hover-sync */ import { chromium } from 'playwright'; const URL = "http://localhost:1999"; async function testHoverSync() { console.log('🔄 HOVER SYNCHRONIZATION TEST\n'); console.log('='.repeat(70)); const browser = await chromium.launch({ headless: false }); const page = await browser.newPage({ viewport: { width: 1920, height: 1080 } }); const errors = []; const testResults = []; // Track errors page.on('console', msg => { if (msg.type() === 'error') { errors.push(msg.text()); console.log(`❌ ERROR: ${msg.text()}`); } }); await page.goto(URL); await page.waitForTimeout(2000); // ======================================================================== // TEST 1: PDF Button Hover Sync (Action Bar → Menu) // ======================================================================== console.log("\n1️⃣ Testing PDF Button Hover Sync (Action Bar → Menu)..."); // Open hamburger menu to make menu buttons visible const hamburger = await page.$('.hamburger-btn'); if (hamburger) { await hamburger.click(); await page.waitForTimeout(500); } const pdfTest1 = await page.evaluate(() => { // Find buttons const actionBarPdf = document.querySelector('#action-bar-pdf-btn'); const menuPdf = document.querySelector('.menu-action-btn'); // First menu-action-btn is PDF if (!actionBarPdf || !menuPdf) { return { found: false, actionBarPdf: !!actionBarPdf, menuPdf: !!menuPdf }; } // Simulate hover on action bar button const mouseEnter = new MouseEvent('mouseenter', { bubbles: true }); actionBarPdf.dispatchEvent(mouseEnter); // Check if both have hover class const actionBarHasClass = actionBarPdf.classList.contains('pdf-hover-sync'); const menuHasClass = menuPdf.classList.contains('pdf-hover-sync'); // Clean up const mouseLeave = new MouseEvent('mouseleave', { bubbles: true }); actionBarPdf.dispatchEvent(mouseLeave); return { found: true, actionBarHasClass, menuHasClass, actionBarClasses: Array.from(actionBarPdf.classList), menuClasses: Array.from(menuPdf.classList) }; }); if (!pdfTest1.found) { console.log(` ❌ FAIL - Buttons not found`); console.log(` Action bar PDF: ${pdfTest1.actionBarPdf ? '✅' : '❌'}`); console.log(` Menu PDF: ${pdfTest1.menuPdf ? '✅' : '❌'}`); testResults.push({ test: 'PDF Hover Sync (Bar→Menu)', passed: false }); } else { console.log(` Action bar button adds class: ${pdfTest1.actionBarHasClass ? '✅' : '❌'}`); console.log(` Menu button gets class: ${pdfTest1.menuHasClass ? '✅' : '❌'}`); console.log(` Action bar classes: ${pdfTest1.actionBarClasses.join(', ')}`); console.log(` Menu classes: ${pdfTest1.menuClasses.join(', ')}`); const passed = pdfTest1.actionBarHasClass && pdfTest1.menuHasClass; console.log(` ${passed ? '✅ PASS' : '❌ FAIL'} - PDF hover sync (bar→menu)`); testResults.push({ test: 'PDF Hover Sync (Bar→Menu)', passed }); } // ======================================================================== // TEST 2: Print Button Hover Sync (Action Bar → Menu) // ======================================================================== console.log("\n2️⃣ Testing Print Button Hover Sync (Action Bar → Menu)..."); const printTest1 = await page.evaluate(() => { const actionBarPrint = document.querySelector('.action-bar-print-btn'); const menuPrint = document.querySelector('.menu-print-btn'); if (!actionBarPrint || !menuPrint) { return { found: false, actionBarPrint: !!actionBarPrint, menuPrint: !!menuPrint }; } // Simulate hover on action bar button const mouseEnter = new MouseEvent('mouseenter', { bubbles: true }); actionBarPrint.dispatchEvent(mouseEnter); // Check if both have hover class const actionBarHasClass = actionBarPrint.classList.contains('print-hover-sync'); const menuHasClass = menuPrint.classList.contains('print-hover-sync'); // Clean up const mouseLeave = new MouseEvent('mouseleave', { bubbles: true }); actionBarPrint.dispatchEvent(mouseLeave); return { found: true, actionBarHasClass, menuHasClass, actionBarClasses: Array.from(actionBarPrint.classList), menuClasses: Array.from(menuPrint.classList) }; }); if (!printTest1.found) { console.log(` ❌ FAIL - Buttons not found`); console.log(` Action bar Print: ${printTest1.actionBarPrint ? '✅' : '❌'}`); console.log(` Menu Print: ${printTest1.menuPrint ? '✅' : '❌'}`); testResults.push({ test: 'Print Hover Sync (Bar→Menu)', passed: false }); } else { console.log(` Action bar button adds class: ${printTest1.actionBarHasClass ? '✅' : '❌'}`); console.log(` Menu button gets class: ${printTest1.menuHasClass ? '✅' : '❌'}`); console.log(` Action bar classes: ${printTest1.actionBarClasses.join(', ')}`); console.log(` Menu classes: ${printTest1.menuClasses.join(', ')}`); const passed = printTest1.actionBarHasClass && printTest1.menuHasClass; console.log(` ${passed ? '✅ PASS' : '❌ FAIL'} - Print hover sync (bar→menu)`); testResults.push({ test: 'Print Hover Sync (Bar→Menu)', passed }); } // ======================================================================== // TEST 3: PDF Button Hover Sync (Menu → Action Bar) // ======================================================================== console.log("\n3️⃣ Testing PDF Button Hover Sync (Menu → Action Bar)..."); const pdfTest2 = await page.evaluate(() => { const actionBarPdf = document.querySelector('#action-bar-pdf-btn'); const menuPdf = document.querySelector('.menu-action-btn'); if (!actionBarPdf || !menuPdf) { return { found: false }; } // Check if menu button has event handlers const hasMouseEnter = menuPdf.getAttribute('_')?.includes('mouseenter'); const hasMouseLeave = menuPdf.getAttribute('_')?.includes('mouseleave'); // Simulate hover on menu button (if it has handlers) if (hasMouseEnter) { const mouseEnter = new MouseEvent('mouseenter', { bubbles: true }); menuPdf.dispatchEvent(mouseEnter); } const actionBarHasClass = actionBarPdf.classList.contains('pdf-hover-sync'); const menuHasClass = menuPdf.classList.contains('pdf-hover-sync'); // Clean up if (hasMouseLeave) { const mouseLeave = new MouseEvent('mouseleave', { bubbles: true }); menuPdf.dispatchEvent(mouseLeave); } return { found: true, hasMouseEnter, hasMouseLeave, actionBarHasClass, menuHasClass }; }); if (!pdfTest2.found) { console.log(` ❌ FAIL - Buttons not found`); testResults.push({ test: 'PDF Hover Sync (Menu→Bar)', passed: false }); } else { console.log(` Menu button has mouseenter handler: ${pdfTest2.hasMouseEnter ? '✅' : '❌'}`); console.log(` Menu button has mouseleave handler: ${pdfTest2.hasMouseLeave ? '✅' : '❌'}`); console.log(` Action bar button gets class: ${pdfTest2.actionBarHasClass ? '✅' : '❌'}`); console.log(` Menu button adds class: ${pdfTest2.menuHasClass ? '✅' : '❌'}`); const passed = pdfTest2.hasMouseEnter && pdfTest2.hasMouseLeave && pdfTest2.actionBarHasClass && pdfTest2.menuHasClass; console.log(` ${passed ? '✅ PASS' : '❌ FAIL'} - PDF hover sync (menu→bar)`); testResults.push({ test: 'PDF Hover Sync (Menu→Bar)', passed }); } // ======================================================================== // TEST 4: Print Button Hover Sync (Menu → Action Bar) // ======================================================================== console.log("\n4️⃣ Testing Print Button Hover Sync (Menu → Action Bar)..."); const printTest2 = await page.evaluate(() => { const actionBarPrint = document.querySelector('.action-bar-print-btn'); const menuPrint = document.querySelector('.menu-print-btn'); if (!actionBarPrint || !menuPrint) { return { found: false }; } // Check if menu button has event handlers const hasMouseEnter = menuPrint.getAttribute('_')?.includes('mouseenter'); const hasMouseLeave = menuPrint.getAttribute('_')?.includes('mouseleave'); // Simulate hover on menu button const mouseEnter = new MouseEvent('mouseenter', { bubbles: true }); menuPrint.dispatchEvent(mouseEnter); const actionBarHasClass = actionBarPrint.classList.contains('print-hover-sync'); const menuHasClass = menuPrint.classList.contains('print-hover-sync'); // Clean up const mouseLeave = new MouseEvent('mouseleave', { bubbles: true }); menuPrint.dispatchEvent(mouseLeave); return { found: true, hasMouseEnter, hasMouseLeave, actionBarHasClass, menuHasClass }; }); if (!printTest2.found) { console.log(` ❌ FAIL - Buttons not found`); testResults.push({ test: 'Print Hover Sync (Menu→Bar)', passed: false }); } else { console.log(` Menu button has mouseenter handler: ${printTest2.hasMouseEnter ? '✅' : '❌'}`); console.log(` Menu button has mouseleave handler: ${printTest2.hasMouseLeave ? '✅' : '❌'}`); console.log(` Action bar button gets class: ${printTest2.actionBarHasClass ? '✅' : '❌'}`); console.log(` Menu button adds class: ${printTest2.menuHasClass ? '✅' : '❌'}`); const passed = printTest2.hasMouseEnter && printTest2.hasMouseLeave && printTest2.actionBarHasClass && printTest2.menuHasClass; console.log(` ${passed ? '✅ PASS' : '❌ FAIL'} - Print hover sync (menu→bar)`); testResults.push({ test: 'Print Hover Sync (Menu→Bar)', passed }); } // ======================================================================== // TEST 5: Visual hover test (manual verification) // ======================================================================== console.log("\n5️⃣ Manual Visual Test..."); console.log(" Please hover over the following and verify visual sync:"); console.log(" 1. Hover action bar PDF button → menu PDF should highlight"); console.log(" 2. Hover action bar Print button → menu Print should highlight"); console.log(" 3. Hover menu PDF button → action bar PDF should highlight"); console.log(" 4. Hover menu Print button → action bar Print should highlight"); // ======================================================================== // FINAL SUMMARY // ======================================================================== console.log("\n" + "=".repeat(70)); console.log("📊 TEST SUMMARY\n"); const totalTests = testResults.length; const passedTests = testResults.filter(r => r.passed).length; const failedTests = totalTests - passedTests; testResults.forEach(result => { console.log(` ${result.passed ? '✅' : '❌'} ${result.test}`); }); console.log(`\n Total: ${passedTests}/${totalTests} tests passed`); if (errors.length === 0) { console.log("\n✅ NO CONSOLE ERRORS"); } else { console.log(`\n⚠️ ${errors.length} CONSOLE ERRORS`); } console.log("=".repeat(70) + "\n"); if (failedTests === 0) { console.log("🎉 ALL HOVER SYNC TESTS PASSED!"); } else { console.log("⚠️ SOME TESTS FAILED - Hover synchronization broken"); console.log("\nExpected bug locations:"); console.log(" - templates/partials/navigation/hamburger-menu.html (missing mouseenter/leave on PDF button)"); console.log(" - static/js/cv-functions.js (hover sync functions exist but not called properly)"); } console.log("\nBrowser will stay open for manual verification."); console.log("Press Ctrl+C when done.\n"); await new Promise(() => {}); // Keep browser open } await testHoverSync();