#!/usr/bin/env node /** * Test: Mobile Updates Verification * * Verifies the updated mobile features: * 1. Keyboard shortcuts button is visible * 2. All 6 buttons are positioned in a single row * 3. Footer has 120px bottom padding * 4. Footer hover effect enlarges text */ import { chromium } from 'playwright'; const TEST_URL = 'http://localhost:1999'; const VIEWPORT_WIDTH = 375; // Mobile width const VIEWPORT_HEIGHT = 812; // iPhone X height async function testMobileUpdates() { console.log('๐Ÿงช Testing Mobile Updates (6-Button Row, Footer Padding, Hover Effect)'); console.log('='.repeat(70)); const browser = await chromium.launch({ headless: true }); const context = await browser.newContext({ viewport: { width: VIEWPORT_WIDTH, height: VIEWPORT_HEIGHT }, deviceScaleFactor: 2, }); const page = await context.newPage(); // Disable cache await page.route('**/*', (route) => { route.continue({ headers: { ...route.request().headers(), 'Cache-Control': 'no-cache, no-store, must-revalidate', }, }); }); try { await page.goto(TEST_URL, { waitUntil: 'networkidle' }); console.log(`โœ… Navigated to ${TEST_URL}`); await page.waitForTimeout(1500); let allTestsPassed = true; // TEST 1: Keyboard shortcuts button should be visible on mobile console.log('\n๐Ÿ“Š TEST 1: Keyboard shortcuts button visible on mobile'); console.log('-'.repeat(70)); const shortcutsBtn = await page.$('.shortcuts-btn'); if (shortcutsBtn) { const isVisible = await shortcutsBtn.isVisible(); if (isVisible) { console.log('โœ… Keyboard shortcuts button is visible on mobile'); } else { console.log('โŒ Keyboard shortcuts button is hidden (should be visible)'); allTestsPassed = false; } } else { console.log('โŒ Keyboard shortcuts button not found in DOM'); allTestsPassed = false; } // TEST 2: All 6 buttons should be positioned in a row console.log('\n๐Ÿ“Š TEST 2: All 6 buttons positioned in a row'); console.log('-'.repeat(70)); const buttonPositions = await page.evaluate(() => { const buttons = [ { name: 'Download', selector: '.download-btn' }, { name: 'Print', selector: '.print-friendly-btn' }, { name: 'Shortcuts', selector: '.shortcuts-btn' }, { name: 'Theme', selector: '.color-theme-switcher' }, { name: 'Info', selector: '.info-button' }, { name: 'Back-to-top', selector: '.back-to-top' } ]; return buttons.map(({ name, selector }) => { const btn = document.querySelector(selector); if (!btn) return { name, exists: false }; const rect = btn.getBoundingClientRect(); const styles = window.getComputedStyle(btn); return { name, exists: true, bottom: rect.bottom, left: rect.left, width: rect.width, position: styles.position }; }); }); // Check all buttons exist and are at same bottom position const bottomPosition = buttonPositions[0]?.bottom; let allButtonsAligned = true; for (const btn of buttonPositions) { if (!btn.exists) { console.log(`โŒ ${btn.name}: Button not found`); allTestsPassed = false; allButtonsAligned = false; } else { const bottomMatch = Math.abs(btn.bottom - bottomPosition) < 5; // 5px tolerance if (bottomMatch) { console.log(`โœ… ${btn.name}: Positioned at bottom=${btn.bottom.toFixed(0)}px, left=${btn.left.toFixed(0)}px`); } else { console.log(`โŒ ${btn.name}: Wrong bottom position (${btn.bottom.toFixed(0)}px, expected ~${bottomPosition.toFixed(0)}px)`); allTestsPassed = false; allButtonsAligned = false; } } } if (allButtonsAligned && buttonPositions.every(b => b.exists)) { console.log('โœ… All 6 buttons are aligned in a row'); } // TEST 3: Footer should have 120px bottom padding console.log('\n๐Ÿ“Š TEST 3: Footer has 120px bottom padding'); console.log('-'.repeat(70)); await page.evaluate(() => { window.scrollTo(0, document.body.scrollHeight); }); await page.waitForTimeout(500); const footerPadding = await page.evaluate(() => { const footer = document.querySelector('footer.no-print'); if (!footer) return { exists: false }; const styles = window.getComputedStyle(footer); return { exists: true, paddingBottom: styles.paddingBottom, paddingBottomValue: parseInt(styles.paddingBottom, 10) }; }); if (footerPadding.exists) { if (footerPadding.paddingBottomValue >= 110) { console.log(`โœ… Footer has adequate padding: ${footerPadding.paddingBottom}`); } else { console.log(`โŒ Footer padding insufficient: ${footerPadding.paddingBottom} (expected >= 110px)`); allTestsPassed = false; } } else { console.log('โŒ Footer element not found'); allTestsPassed = false; } // TEST 4: Footer hover effect should enlarge text console.log('\n๐Ÿ“Š TEST 4: Footer hover effect enlarges text'); console.log('-'.repeat(70)); // Get initial font size const initialFontSize = await page.evaluate(() => { const footer = document.querySelector('footer.no-print p'); if (!footer) return null; return parseFloat(window.getComputedStyle(footer).fontSize); }); // Trigger footer hover by adding class await page.evaluate(() => { const footer = document.querySelector('footer.no-print'); if (footer) { footer.classList.add('footer-hovered'); // Trigger transition footer.offsetHeight; // Force reflow } }); await page.waitForTimeout(500); // Wait for CSS transition const hoveredFontSize = await page.evaluate(() => { const footer = document.querySelector('footer.no-print p'); if (!footer) return null; return parseFloat(window.getComputedStyle(footer).fontSize); }); if (initialFontSize && hoveredFontSize) { if (hoveredFontSize > initialFontSize) { console.log(`โœ… Footer text enlarged on hover: ${initialFontSize.toFixed(1)}px โ†’ ${hoveredFontSize.toFixed(1)}px`); } else { console.log(`โŒ Footer text not enlarged: ${initialFontSize.toFixed(1)}px โ†’ ${hoveredFontSize.toFixed(1)}px`); allTestsPassed = false; } } else { console.log('โŒ Could not measure footer font sizes'); allTestsPassed = false; } console.log('-'.repeat(70)); if (allTestsPassed) { console.log('\nโœ… ALL TESTS PASSED!'); console.log(' โ€ข Keyboard shortcuts button visible'); console.log(' โ€ข All 6 buttons in a single row'); console.log(' โ€ข Footer has 120px bottom padding'); console.log(' โ€ข Footer hover effect enlarges text'); } else { console.log('\nโŒ SOME TESTS FAILED - Check output above'); } await browser.close(); process.exit(allTestsPassed ? 0 : 1); } catch (error) { console.error('\nโŒ Test error:', error); await browser.close(); process.exit(1); } } testMobileUpdates();