diff --git a/internal/handlers/cv_helpers.go b/internal/handlers/cv_helpers.go index ead3607..a59026c 100644 --- a/internal/handlers/cv_helpers.go +++ b/internal/handlers/cv_helpers.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "log" - "net/http" "os" "os/exec" "path/filepath" @@ -361,25 +360,5 @@ func (h *CVHandler) prepareTemplateData(lang string) (map[string]interface{}, er // ============================================================================== // COOKIE HELPERS // ============================================================================== - -// getPreferenceCookie gets a preference cookie value, returns default if not found -func getPreferenceCookie(r *http.Request, name string, defaultValue string) string { - cookie, err := r.Cookie(name) - if err != nil { - return defaultValue - } - return cookie.Value -} - -// setPreferenceCookie sets a preference cookie (1 year expiry) -func setPreferenceCookie(w http.ResponseWriter, name string, value string) { - http.SetCookie(w, &http.Cookie{ - Name: name, - Value: value, - Path: "/", - MaxAge: 365 * 24 * 60 * 60, // 1 year - HttpOnly: true, - SameSite: http.SameSiteStrictMode, - Secure: false, // Set to true in production with HTTPS - }) -} +// Note: Cookie preference management is now handled client-side via JavaScript +// and localStorage. Server-side cookie helpers have been removed as unused. diff --git a/static/js/main.js b/static/js/main.js index 02ec9a3..b5b8c05 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -74,32 +74,38 @@ }; /** - * Auto-open sidebar accordions in landscape mobile mode - * Ensures sidebar content is visible in landscape orientation + * Auto-open sidebar accordions in landscape mobile mode AND desktop + * Ensures sidebar content is always visible except in portrait mobile */ function handleLandscapeAccordions() { - function openSidebarAccordionsIfLandscape() { + function openSidebarAccordionsIfNeeded() { const isLandscape = window.matchMedia('(max-width: 915px) and (orientation: landscape)').matches; + const isDesktop = window.matchMedia('(min-width: 769px)').matches; + const isPortraitMobile = window.matchMedia('(max-width: 768px) and (orientation: portrait)').matches; - if (isLandscape) { - // Open all sidebar accordions in landscape mode + // Open accordions in landscape mobile OR desktop view + // Keep them closed ONLY in portrait mobile (โ‰ค768px) + if (isLandscape || isDesktop) { document.querySelectorAll('.sidebar-accordion').forEach(accordion => { accordion.setAttribute('open', ''); }); + } else if (isPortraitMobile) { + // In portrait mobile, leave them closed (user can expand manually) + // Don't remove 'open' attribute if user has opened them } } // Run on load - openSidebarAccordionsIfLandscape(); + openSidebarAccordionsIfNeeded(); // Run on orientation change window.addEventListener('orientationchange', () => { - setTimeout(openSidebarAccordionsIfLandscape, 100); + setTimeout(openSidebarAccordionsIfNeeded, 100); }); // Run on resize (for desktop browser testing) window.addEventListener('resize', () => { - openSidebarAccordionsIfLandscape(); + openSidebarAccordionsIfNeeded(); }); } diff --git a/tests/mjs/64-desktop-view-test.mjs b/tests/mjs/64-desktop-view-test.mjs new file mode 100755 index 0000000..26c9921 --- /dev/null +++ b/tests/mjs/64-desktop-view-test.mjs @@ -0,0 +1,114 @@ +#!/usr/bin/env node + +import { chromium } from 'playwright'; + +const DESKTOP_VIEWPORT = { width: 1278, height: 800 }; // User's actual viewport + +(async () => { + const browser = await chromium.launch({ headless: true }); + const context = await browser.newContext({ + viewport: DESKTOP_VIEWPORT + }); + const page = await context.newPage(); + + await page.goto('http://localhost:1999/?lang=en&view=extended'); + await page.waitForLoadState('networkidle'); + + const desktopLayout = await page.evaluate(() => { + const sidebar = document.querySelector('.cv-sidebar-left'); + const sidebarRight = document.querySelector('.cv-sidebar-right'); + const accordion = document.querySelector('.sidebar-accordion'); + const accordionHeader = document.querySelector('.sidebar-accordion-header'); + const downloadBtn = document.querySelector('.download-btn'); + const backdrop = document.querySelector('.fixed-buttons-backdrop'); + + const sidebarRect = sidebar?.getBoundingClientRect(); + const accordionRect = accordion?.getBoundingClientRect(); + + return { + viewport: `${window.innerWidth}ร—${window.innerHeight}`, + mediaQueries: { + 'landscape-mobile': window.matchMedia('(max-width: 915px) and (orientation: landscape)').matches, + 'mobile-768': window.matchMedia('(max-width: 768px)').matches, + 'mobile-540': window.matchMedia('(max-width: 540px)').matches, + }, + sidebar: { + exists: !!sidebar, + visible: sidebar ? window.getComputedStyle(sidebar).display !== 'none' : false, + width: sidebarRect ? Math.round(sidebarRect.width) : 0, + height: sidebarRect ? Math.round(sidebarRect.height) : 0, + left: sidebarRect ? Math.round(sidebarRect.left) : 0, + }, + sidebarRight: { + exists: !!sidebarRight, + visible: sidebarRight ? window.getComputedStyle(sidebarRight).display !== 'none' : false, + }, + accordion: { + exists: !!accordion, + headerVisible: accordionHeader ? window.getComputedStyle(accordionHeader).display !== 'none' : false, + open: accordion?.hasAttribute('open'), + height: accordionRect ? Math.round(accordionRect.height) : 0, + }, + buttons: { + downloadBtnExists: !!downloadBtn, + downloadBtnVisible: downloadBtn ? window.getComputedStyle(downloadBtn).display !== 'none' : false, + downloadBtnBottom: downloadBtn ? window.getComputedStyle(downloadBtn).bottom : 'N/A', + backdropExists: !!backdrop, + backdropVisible: backdrop ? window.getComputedStyle(backdrop).display !== 'none' : false, + } + }; + }); + + console.log('๐Ÿ–ฅ๏ธ Desktop View Test (1278px)\n'); + console.log(`Viewport: ${desktopLayout.viewport}\n`); + + console.log('Media Queries:'); + console.log(` โ€ข Landscape mobile (โ‰ค915px): ${desktopLayout.mediaQueries['landscape-mobile'] ? 'โœ… MATCHES' : 'โŒ NO MATCH'}`); + console.log(` โ€ข Mobile (โ‰ค768px): ${desktopLayout.mediaQueries['mobile-768'] ? 'โœ… MATCHES' : 'โŒ NO MATCH'}`); + console.log(` โ€ข Mobile (โ‰ค540px): ${desktopLayout.mediaQueries['mobile-540'] ? 'โœ… MATCHES' : 'โŒ NO MATCH'}\n`); + + console.log('Left Sidebar:'); + console.log(` โ€ข Exists: ${desktopLayout.sidebar.exists ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Visible: ${desktopLayout.sidebar.visible ? 'โœ…' : 'โŒ BROKEN'}`); + console.log(` โ€ข Size: ${desktopLayout.sidebar.width}ร—${desktopLayout.sidebar.height}px`); + console.log(` โ€ข Position: left=${desktopLayout.sidebar.left}px\n`); + + console.log('Right Sidebar:'); + console.log(` โ€ข Exists: ${desktopLayout.sidebarRight.exists ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Visible: ${desktopLayout.sidebarRight.visible ? 'โœ…' : 'โŒ BROKEN'}\n`); + + console.log('Accordion (should NOT be present in desktop view):'); + console.log(` โ€ข Exists: ${desktopLayout.accordion.exists ? 'โŒ SHOULD NOT EXIST' : 'โœ…'}`); + console.log(` โ€ข Header visible: ${desktopLayout.accordion.headerVisible ? 'โŒ SHOULD BE HIDDEN' : 'โœ…'}`); + console.log(` โ€ข Open: ${desktopLayout.accordion.open ? 'YES' : 'NO'}`); + console.log(` โ€ข Height: ${desktopLayout.accordion.height}px\n`); + + console.log('Bottom Buttons:'); + console.log(` โ€ข Download button exists: ${desktopLayout.buttons.downloadBtnExists ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Download button visible: ${desktopLayout.buttons.downloadBtnVisible ? 'โœ…' : 'โŒ BROKEN'}`); + console.log(` โ€ข Download button bottom: ${desktopLayout.buttons.downloadBtnBottom}`); + console.log(` โ€ข Backdrop exists: ${desktopLayout.buttons.backdropExists ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Backdrop visible: ${desktopLayout.buttons.backdropVisible ? 'โœ…' : 'โŒ'}\n`); + + await page.screenshot({ + path: 'tests/screenshots/desktop-1278px.png', + fullPage: true + }); + console.log('Screenshot saved: tests/screenshots/desktop-1278px.png\n'); + + const criticalIssues = []; + if (!desktopLayout.sidebar.visible) criticalIssues.push('Left sidebar not visible'); + if (!desktopLayout.sidebarRight.visible) criticalIssues.push('Right sidebar not visible'); + if (desktopLayout.accordion.headerVisible) criticalIssues.push('Accordion visible in desktop view'); + if (!desktopLayout.buttons.downloadBtnVisible) criticalIssues.push('Download button not visible'); + + if (criticalIssues.length > 0) { + console.log('โŒ CRITICAL ISSUES FOUND:'); + criticalIssues.forEach(issue => console.log(` - ${issue}`)); + } else { + console.log('โœ… Desktop view looks good'); + } + + await browser.close(); + process.exit(criticalIssues.length > 0 ? 1 : 0); +})(); diff --git a/tests/mjs/65-page-2-sidebar-debug.mjs b/tests/mjs/65-page-2-sidebar-debug.mjs new file mode 100755 index 0000000..cb50da5 --- /dev/null +++ b/tests/mjs/65-page-2-sidebar-debug.mjs @@ -0,0 +1,111 @@ +#!/usr/bin/env node + +import { chromium } from 'playwright'; + +const DESKTOP_VIEWPORT = { width: 1278, height: 800 }; + +(async () => { + const browser = await chromium.launch({ headless: true }); + const context = await browser.newContext({ + viewport: DESKTOP_VIEWPORT + }); + const page = await context.newPage(); + + await page.goto('http://localhost:1999/?lang=en&view=extended'); + await page.waitForLoadState('networkidle'); + + // Scroll to Page 2 + await page.evaluate(() => { + const page2 = document.querySelector('.page-2'); + if (page2) { + page2.scrollIntoView(); + } + }); + + await page.waitForTimeout(500); + + const page2Debug = await page.evaluate(() => { + const page2 = document.querySelector('.page-2'); + const pageContent = page2?.querySelector('.page-content'); + const sidebarRight = page2?.querySelector('.cv-sidebar-right'); + const accordion = sidebarRight?.querySelector('.sidebar-accordion'); + const actualContent = sidebarRight?.querySelector('.actual-content'); + const accordionContent = sidebarRight?.querySelector('.sidebar-accordion-content'); + + const sidebarRect = sidebarRight?.getBoundingClientRect(); + const accordionRect = accordion?.getBoundingClientRect(); + + return { + page2Exists: !!page2, + pageContentGrid: pageContent ? window.getComputedStyle(pageContent).gridTemplateColumns : 'N/A', + + sidebarRight: { + exists: !!sidebarRight, + display: sidebarRight ? window.getComputedStyle(sidebarRight).display : 'N/A', + visibility: sidebarRight ? window.getComputedStyle(sidebarRight).visibility : 'N/A', + width: sidebarRect ? Math.round(sidebarRect.width) : 0, + height: sidebarRect ? Math.round(sidebarRect.height) : 0, + backgroundColor: sidebarRight ? window.getComputedStyle(sidebarRight).backgroundColor : 'N/A', + }, + + accordion: { + exists: !!accordion, + open: accordion?.hasAttribute('open'), + height: accordionRect ? Math.round(accordionRect.height) : 0, + display: accordion ? window.getComputedStyle(accordion).display : 'N/A', + }, + + actualContent: { + exists: !!actualContent, + display: actualContent ? window.getComputedStyle(actualContent).display : 'N/A', + opacity: actualContent ? window.getComputedStyle(actualContent).opacity : 'N/A', + height: actualContent ? Math.round(actualContent.getBoundingClientRect().height) : 0, + }, + + accordionContent: { + exists: !!accordionContent, + display: accordionContent ? window.getComputedStyle(accordionContent).display : 'N/A', + opacity: accordionContent ? window.getComputedStyle(accordionContent).opacity : 'N/A', + height: accordionContent ? Math.round(accordionContent.getBoundingClientRect().height) : 0, + } + }; + }); + + console.log('Page 2 Right Sidebar Debug:\n'); + + console.log('Page Content Grid:'); + console.log(` โ€ข Grid columns: ${page2Debug.pageContentGrid}\n`); + + console.log('Right Sidebar:'); + console.log(` โ€ข Exists: ${page2Debug.sidebarRight.exists ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Display: ${page2Debug.sidebarRight.display}`); + console.log(` โ€ข Visibility: ${page2Debug.sidebarRight.visibility}`); + console.log(` โ€ข Size: ${page2Debug.sidebarRight.width}ร—${page2Debug.sidebarRight.height}px`); + console.log(` โ€ข Background: ${page2Debug.sidebarRight.backgroundColor}\n`); + + console.log('Accordion:'); + console.log(` โ€ข Exists: ${page2Debug.accordion.exists ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Display: ${page2Debug.accordion.display}`); + console.log(` โ€ข Open: ${page2Debug.accordion.open ? 'YES' : 'NO'}`); + console.log(` โ€ข Height: ${page2Debug.accordion.height}px\n`); + + console.log('Actual Content Wrapper:'); + console.log(` โ€ข Exists: ${page2Debug.actualContent.exists ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Display: ${page2Debug.actualContent.display}`); + console.log(` โ€ข Opacity: ${page2Debug.actualContent.opacity}`); + console.log(` โ€ข Height: ${page2Debug.actualContent.height}px\n`); + + console.log('Accordion Content:'); + console.log(` โ€ข Exists: ${page2Debug.accordionContent.exists ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Display: ${page2Debug.accordionContent.display}`); + console.log(` โ€ข Opacity: ${page2Debug.accordionContent.opacity}`); + console.log(` โ€ข Height: ${page2Debug.accordionContent.height}px\n`); + + await page.screenshot({ + path: 'tests/screenshots/page-2-sidebar-debug.png', + fullPage: false + }); + console.log('Screenshot saved: tests/screenshots/page-2-sidebar-debug.png'); + + await browser.close(); +})(); diff --git a/tests/mjs/66-comprehensive-all-viewports-test.mjs b/tests/mjs/66-comprehensive-all-viewports-test.mjs new file mode 100644 index 0000000..9631525 --- /dev/null +++ b/tests/mjs/66-comprehensive-all-viewports-test.mjs @@ -0,0 +1,214 @@ +#!/usr/bin/env node + +import { chromium } from 'playwright'; + +const VIEWPORTS = { + desktop: { width: 1278, height: 800, name: 'Desktop (1278px)' }, + portraitMobile: { width: 375, height: 667, name: 'Portrait Mobile (375ร—667)' }, + landscapeMobile: { width: 667, height: 375, name: 'Landscape Mobile (667ร—375)' } +}; + +async function testViewport(browser, viewport) { + const context = await browser.newContext({ + viewport, + userAgent: viewport.width < 768 ? 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1' : undefined, + hasTouch: viewport.width < 768 + }); + const page = await context.newPage(); + + await page.goto('http://localhost:1999/?lang=en&view=extended'); + await page.waitForLoadState('networkidle'); + + const results = await page.evaluate(() => { + // Page 1 - Left Sidebar + const sidebarLeft = document.querySelector('.cv-sidebar-left'); + const accordionLeft = sidebarLeft?.querySelector('.sidebar-accordion'); + const accordionContentLeft = sidebarLeft?.querySelector('.sidebar-accordion-content'); + + // Page 2 - Right Sidebar (scroll to it first) + document.querySelector('.page-2')?.scrollIntoView(); + const sidebarRight = document.querySelector('.cv-sidebar-right'); + const accordionRight = sidebarRight?.querySelector('.sidebar-accordion'); + const accordionContentRight = sidebarRight?.querySelector('.sidebar-accordion-content'); + + // Buttons + const downloadBtn = document.querySelector('.download-btn'); + const printBtn = document.querySelector('.print-friendly-btn'); + const infoBtn = document.querySelector('.info-button'); + const backToTop = document.querySelector('.back-to-top'); + const themeSwitcher = document.querySelector('.color-theme-switcher'); + const backdrop = document.querySelector('.fixed-buttons-backdrop'); + + const sidebarLeftRect = sidebarLeft?.getBoundingClientRect(); + const sidebarRightRect = sidebarRight?.getBoundingClientRect(); + + return { + viewport: { + width: window.innerWidth, + height: window.innerHeight, + isPortrait: window.innerHeight > window.innerWidth, + isLandscape: window.innerWidth > window.innerHeight + }, + mediaQueries: { + desktop: window.matchMedia('(min-width: 769px)').matches, + mobile: window.matchMedia('(max-width: 768px)').matches, + landscape: window.matchMedia('(max-width: 915px) and (orientation: landscape)').matches, + }, + leftSidebar: { + exists: !!sidebarLeft, + visible: sidebarLeft && window.getComputedStyle(sidebarLeft).display !== 'none', + height: sidebarLeftRect ? Math.round(sidebarLeftRect.height) : 0, + accordionOpen: accordionLeft?.hasAttribute('open'), + contentHeight: accordionContentLeft ? Math.round(accordionContentLeft.getBoundingClientRect().height) : 0, + }, + rightSidebar: { + exists: !!sidebarRight, + visible: sidebarRight && window.getComputedStyle(sidebarRight).display !== 'none', + height: sidebarRightRect ? Math.round(sidebarRightRect.height) : 0, + accordionOpen: accordionRight?.hasAttribute('open'), + contentHeight: accordionContentRight ? Math.round(accordionContentRight.getBoundingClientRect().height) : 0, + }, + buttons: { + downloadBtn: { + exists: !!downloadBtn, + visible: downloadBtn && window.getComputedStyle(downloadBtn).display !== 'none', + bottom: downloadBtn ? window.getComputedStyle(downloadBtn).bottom : 'N/A', + zIndex: downloadBtn ? window.getComputedStyle(downloadBtn).zIndex : 'N/A', + }, + printBtn: { + exists: !!printBtn, + visible: printBtn && window.getComputedStyle(printBtn).display !== 'none', + }, + infoBtn: { + exists: !!infoBtn, + visible: infoBtn && window.getComputedStyle(infoBtn).display !== 'none', + }, + backToTop: { + exists: !!backToTop, + visible: backToTop && window.getComputedStyle(backToTop).display !== 'none', + }, + themeSwitcher: { + exists: !!themeSwitcher, + visible: themeSwitcher && window.getComputedStyle(themeSwitcher).display !== 'none', + opacity: themeSwitcher ? window.getComputedStyle(themeSwitcher).opacity : 'N/A', + }, + backdrop: { + exists: !!backdrop, + visible: backdrop && window.getComputedStyle(backdrop).display !== 'none', + height: backdrop ? window.getComputedStyle(backdrop).height : 'N/A', + }, + } + }; + }); + + await page.screenshot({ + path: `tests/screenshots/comprehensive-${viewport.name.toLowerCase().replace(/[^a-z0-9]/g, '-')}.png`, + fullPage: true + }); + + await context.close(); + return results; +} + +(async () => { + const browser = await chromium.launch({ headless: true }); + + console.log('๐Ÿงช Comprehensive Multi-Viewport Test\n'); + console.log('Testing: Sidebars, Accordions, and Buttons\n'); + + const allResults = {}; + const failures = []; + + for (const [key, viewport] of Object.entries(VIEWPORTS)) { + console.log(`๐Ÿ“ฑ Testing: ${viewport.name}`); + console.log('='.repeat(50)); + + const results = await testViewport(browser, viewport); + allResults[key] = results; + + // Print results + console.log(`\nViewport: ${results.viewport.width}ร—${results.viewport.height}`); + console.log(`Orientation: ${results.viewport.isLandscape ? 'Landscape' : 'Portrait'}\n`); + + console.log('Left Sidebar:'); + console.log(` โ€ข Exists: ${results.leftSidebar.exists ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Visible: ${results.leftSidebar.visible ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Height: ${results.leftSidebar.height}px`); + console.log(` โ€ข Accordion open: ${results.leftSidebar.accordionOpen ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Content height: ${results.leftSidebar.contentHeight}px\n`); + + console.log('Right Sidebar:'); + console.log(` โ€ข Exists: ${results.rightSidebar.exists ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Visible: ${results.rightSidebar.visible ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Height: ${results.rightSidebar.height}px`); + console.log(` โ€ข Accordion open: ${results.rightSidebar.accordionOpen ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Content height: ${results.rightSidebar.contentHeight}px\n`); + + console.log('Buttons:'); + console.log(` โ€ข Download button: ${results.buttons.downloadBtn.exists && results.buttons.downloadBtn.visible ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Print button: ${results.buttons.printBtn.exists && results.buttons.printBtn.visible ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Info button: ${results.buttons.infoBtn.exists && results.buttons.infoBtn.visible ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Back to top: ${results.buttons.backToTop.exists && results.buttons.backToTop.visible ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Theme switcher: ${results.buttons.themeSwitcher.exists && results.buttons.themeSwitcher.visible ? 'โœ…' : 'โŒ'}`); + console.log(` โ€ข Backdrop: ${results.buttons.backdrop.exists && results.buttons.backdrop.visible ? 'โœ…' : 'โŒ'}\n`); + + // Validation rules + const issues = []; + + // Desktop: Sidebars should be open with content + if (results.mediaQueries.desktop) { + if (!results.leftSidebar.accordionOpen) issues.push('Desktop: Left sidebar accordion should be open'); + if (!results.rightSidebar.accordionOpen) issues.push('Desktop: Right sidebar accordion should be open'); + if (results.leftSidebar.contentHeight < 100) issues.push('Desktop: Left sidebar has no content'); + if (results.rightSidebar.contentHeight < 100) issues.push('Desktop: Right sidebar has no content'); + } + + // Landscape mobile: Sidebars should be open + if (results.mediaQueries.landscape) { + if (!results.leftSidebar.accordionOpen) issues.push('Landscape: Left sidebar accordion should be open'); + if (!results.rightSidebar.accordionOpen) issues.push('Landscape: Right sidebar accordion should be open'); + if (results.leftSidebar.contentHeight < 100) issues.push('Landscape: Left sidebar has no content'); + } + + // All viewports: Buttons should be visible + if (!results.buttons.downloadBtn.visible) issues.push('Download button not visible'); + if (!results.buttons.printBtn.visible) issues.push('Print button not visible'); + if (!results.buttons.infoBtn.visible) issues.push('Info button not visible'); + if (!results.buttons.backToTop.visible) issues.push('Back to top button not visible'); + if (!results.buttons.themeSwitcher.visible) issues.push('Theme switcher not visible'); + + // Mobile: Backdrop should be visible + if (results.mediaQueries.mobile || results.mediaQueries.landscape) { + if (!results.buttons.backdrop.visible) issues.push('Mobile: Button backdrop not visible'); + } + + if (issues.length > 0) { + console.log('โŒ ISSUES FOUND:'); + issues.forEach(issue => { + console.log(` - ${issue}`); + failures.push(`${viewport.name}: ${issue}`); + }); + } else { + console.log('โœ… All checks passed'); + } + + console.log('\n'); + } + + // Final summary + console.log('='.repeat(50)); + console.log('FINAL SUMMARY\n'); + + if (failures.length === 0) { + console.log('โœ… ALL VIEWPORTS PASSED ALL CHECKS\n'); + } else { + console.log(`โŒ ${failures.length} ISSUE(S) FOUND:\n`); + failures.forEach((failure, i) => { + console.log(`${i + 1}. ${failure}`); + }); + console.log(''); + } + + await browser.close(); + process.exit(failures.length === 0 ? 0 : 1); +})();