#!/usr/bin/env bun /** * ZOOM UI EXCLUSION TEST * ======================= * Verifies that UI elements (footer, menu, buttons) are NOT affected by zoom * * Test Requirements: * - Footer should NOT be inside #zoom-wrapper * - Action bar should NOT be inside #zoom-wrapper * - Hamburger menu should NOT be inside #zoom-wrapper * - Fixed buttons should NOT be inside #zoom-wrapper * - Only .cv-container content should be affected by zoom * * Test Flow: * 1. Load page and show zoom control * 2. Measure initial sizes of UI elements * 3. Set zoom to 200% * 4. Verify UI elements remain same size * 5. Verify CV content has doubled in size */ import { chromium } from "playwright"; const URL = "http://localhost:1999"; async function testZoomUIExclusion() { console.log("๐Ÿงช ZOOM UI EXCLUSION TEST\n"); console.log("=".repeat(70)); const browser = await chromium.launch({ headless: false }); const page = await browser.newPage({ viewport: { width: 1400, height: 1080 } }); const errors = []; const testResults = []; page.on('console', msg => { const text = msg.text(); if (msg.type() === 'error') { errors.push(text); console.log(`โŒ ERROR: ${text}`); } }); page.on('pageerror', err => { errors.push(err.message); console.log(`โŒ PAGE ERROR: ${err.message}`); }); // ======================================================================== // TEST 1: Verify DOM Structure // ======================================================================== console.log("\n1๏ธโƒฃ Verifying DOM structure (UI outside zoom-wrapper)..."); await page.goto(URL); await page.waitForTimeout(2000); // Set zoom visible await page.evaluate(() => localStorage.setItem('cv-zoom-visible', 'true')); await page.reload(); await page.waitForTimeout(2000); // Check that footer is NOT inside zoom-wrapper const footerOutsideZoom = await page.evaluate(() => { const footer = document.querySelector('.page-footer'); const zoomWrapper = document.querySelector('#zoom-wrapper'); if (!footer || !zoomWrapper) return false; return !zoomWrapper.contains(footer); }); // Check that action bar is NOT inside zoom-wrapper const actionBarOutsideZoom = await page.evaluate(() => { const actionBar = document.querySelector('.action-bar'); const zoomWrapper = document.querySelector('#zoom-wrapper'); if (!actionBar || !zoomWrapper) return false; return !zoomWrapper.contains(actionBar); }); // Check that hamburger menu is NOT inside zoom-wrapper const menuOutsideZoom = await page.evaluate(() => { const menu = document.querySelector('.navigation-menu'); const zoomWrapper = document.querySelector('#zoom-wrapper'); if (!menu || !zoomWrapper) return false; return !zoomWrapper.contains(menu); }); // Check that CV content IS inside zoom-wrapper const cvInsideZoom = await page.evaluate(() => { const cv = document.querySelector('.cv-container'); const zoomWrapper = document.querySelector('#zoom-wrapper'); if (!cv || !zoomWrapper) return false; return zoomWrapper.contains(cv); }); const test1Passed = footerOutsideZoom && actionBarOutsideZoom && menuOutsideZoom && cvInsideZoom; console.log(` Footer outside zoom-wrapper: ${footerOutsideZoom ? 'โœ… YES' : 'โŒ NO'}`); console.log(` Action bar outside zoom-wrapper: ${actionBarOutsideZoom ? 'โœ… YES' : 'โŒ NO'}`); console.log(` Menu outside zoom-wrapper: ${menuOutsideZoom ? 'โœ… YES' : 'โŒ NO'}`); console.log(` CV content inside zoom-wrapper: ${cvInsideZoom ? 'โœ… YES' : 'โŒ NO'}`); console.log(` ${test1Passed ? 'โœ… PASS' : 'โŒ FAIL'}`); testResults.push({ test: 'DOM Structure - UI Outside Zoom', passed: test1Passed }); // ======================================================================== // TEST 2: Measure UI Elements at 100% Zoom // ======================================================================== console.log("\n2๏ธโƒฃ Measuring UI elements at 100% zoom..."); const initialSizes = await page.evaluate(() => { const footer = document.querySelector('.page-footer'); const actionBar = document.querySelector('.action-bar'); const cvPaper = document.querySelector('.cv-paper'); return { footerHeight: footer ? footer.offsetHeight : 0, actionBarHeight: actionBar ? actionBar.offsetHeight : 0, cvWidth: cvPaper ? cvPaper.offsetWidth : 0, }; }); console.log(` Footer height: ${initialSizes.footerHeight}px`); console.log(` Action bar height: ${initialSizes.actionBarHeight}px`); console.log(` CV width: ${initialSizes.cvWidth}px`); // ======================================================================== // TEST 3: Set Zoom to 200% and Re-measure // ======================================================================== console.log("\n3๏ธโƒฃ Setting zoom to 200% and re-measuring..."); const slider = await page.$('#zoom-slider'); if (slider) { await slider.evaluate(el => { el.value = '200'; el.dispatchEvent(new Event('input', { bubbles: true })); }); await page.waitForTimeout(500); } const zoomedSizes = await page.evaluate(() => { const footer = document.querySelector('.page-footer'); const actionBar = document.querySelector('.action-bar'); const cvPaper = document.querySelector('.cv-paper'); return { footerHeight: footer ? footer.offsetHeight : 0, actionBarHeight: actionBar ? actionBar.offsetHeight : 0, cvWidth: cvPaper ? cvPaper.offsetWidth : 0, }; }); console.log(` Footer height: ${zoomedSizes.footerHeight}px`); console.log(` Action bar height: ${zoomedSizes.actionBarHeight}px`); console.log(` CV width: ${zoomedSizes.cvWidth}px`); // ======================================================================== // TEST 4: Verify UI Elements Unchanged // ======================================================================== console.log("\n4๏ธโƒฃ Verifying UI elements unchanged at 200% zoom..."); const footerUnchanged = Math.abs(initialSizes.footerHeight - zoomedSizes.footerHeight) < 5; const actionBarUnchanged = Math.abs(initialSizes.actionBarHeight - zoomedSizes.actionBarHeight) < 5; // CV should be approximately doubled (with some tolerance) const cvGrew = zoomedSizes.cvWidth > initialSizes.cvWidth * 1.8; const test4Passed = footerUnchanged && actionBarUnchanged && cvGrew; console.log(` Footer unchanged: ${footerUnchanged ? 'โœ… YES' : 'โŒ NO'} (${initialSizes.footerHeight}px โ†’ ${zoomedSizes.footerHeight}px)`); console.log(` Action bar unchanged: ${actionBarUnchanged ? 'โœ… YES' : 'โŒ NO'} (${initialSizes.actionBarHeight}px โ†’ ${zoomedSizes.actionBarHeight}px)`); console.log(` CV content grew: ${cvGrew ? 'โœ… YES' : 'โŒ NO'} (${initialSizes.cvWidth}px โ†’ ${zoomedSizes.cvWidth}px)`); console.log(` ${test4Passed ? 'โœ… PASS' : 'โŒ FAIL'}`); testResults.push({ test: 'UI Elements Unchanged at 200%', passed: test4Passed }); // ======================================================================== // TEST 5: Reset and Verify // ======================================================================== console.log("\n5๏ธโƒฃ Resetting zoom to 100%..."); const resetBtn = await page.$('#zoom-reset'); if (resetBtn) { await resetBtn.click(); await page.waitForTimeout(500); } const resetSizes = await page.evaluate(() => { const footer = document.querySelector('.page-footer'); const actionBar = document.querySelector('.action-bar'); const cvPaper = document.querySelector('.cv-paper'); return { footerHeight: footer ? footer.offsetHeight : 0, actionBarHeight: actionBar ? actionBar.offsetHeight : 0, cvWidth: cvPaper ? cvPaper.offsetWidth : 0, }; }); const resetPassed = Math.abs(resetSizes.cvWidth - initialSizes.cvWidth) < 10; console.log(` CV width restored: ${resetPassed ? 'โœ… YES' : 'โŒ NO'} (${resetSizes.cvWidth}px vs ${initialSizes.cvWidth}px initial)`); console.log(` ${resetPassed ? 'โœ… PASS' : 'โŒ FAIL'}`); testResults.push({ test: 'Zoom Reset to 100%', passed: resetPassed }); // ======================================================================== // 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 FOUND:\n`); errors.forEach((err, i) => { console.log(`${i + 1}. ${err}`); }); } console.log("=".repeat(70) + "\n"); if (failedTests === 0 && errors.length === 0) { console.log("๐ŸŽ‰ ALL TESTS PASSED! UI elements properly excluded from zoom."); } else { console.log("โš ๏ธ SOME TESTS FAILED - See details above"); } console.log("\nBrowser will stay open for manual inspection."); console.log("Press Ctrl+C when done.\n"); await new Promise(() => {}); // Keep browser open } await testZoomUIExclusion();