// Mobile Testing Utility for Kenneth Reitz Website // Run this in browser console to test mobile optimizations (function() { 'use strict'; const MobileTester = { init() { console.log('šŸš€ Mobile Testing Utility Initialized'); this.runAllTests(); }, // Test viewport and meta tags testViewport() { console.log('\nšŸ“± Testing Viewport Configuration...'); const viewport = document.querySelector('meta[name="viewport"]'); const content = viewport ? viewport.getAttribute('content') : null; if (content && content.includes('width=device-width')) { console.log('āœ… Viewport meta tag configured correctly'); } else { console.warn('āŒ Viewport meta tag missing or incorrect'); } if (content && content.includes('initial-scale=1.0')) { console.log('āœ… Initial scale set correctly'); } else { console.warn('āŒ Initial scale not set'); } }, // Test responsive CSS loading testResponsiveCSS() { console.log('\nšŸŽØ Testing Responsive CSS...'); const mobileCSS = document.querySelector('link[href*="mobile-enhancements.css"]'); const componentsCSS = document.querySelector('link[href*="mobile-components.css"]'); if (mobileCSS) { console.log('āœ… Mobile enhancements CSS loaded'); } else { console.warn('āŒ Mobile enhancements CSS missing'); } if (componentsCSS) { console.log('āœ… Mobile components CSS loaded'); } else { console.warn('āŒ Mobile components CSS missing'); } }, // Test touch targets testTouchTargets() { console.log('\nšŸ‘† Testing Touch Targets...'); const interactive = document.querySelectorAll('a, button, input, textarea, select'); let passCount = 0; let failCount = 0; interactive.forEach(element => { const rect = element.getBoundingClientRect(); const minSize = 44; // iOS recommended minimum if (rect.width >= minSize && rect.height >= minSize) { passCount++; } else { failCount++; if (failCount <= 5) { // Limit console spam console.warn(`āŒ Touch target too small: ${element.tagName} (${Math.round(rect.width)}x${Math.round(rect.height)}px)`); } } }); console.log(`āœ… ${passCount} touch targets meet minimum size`); if (failCount > 0) { console.warn(`āŒ ${failCount} touch targets are too small`); } }, // Test font sizes for readability testFontSizes() { console.log('\nšŸ“– Testing Font Sizes...'); const textElements = document.querySelectorAll('p, span, div, li, td, th'); let tooSmallCount = 0; textElements.forEach(element => { const fontSize = parseFloat(window.getComputedStyle(element).fontSize); if (fontSize < 14 && element.textContent.trim()) { tooSmallCount++; } }); if (tooSmallCount === 0) { console.log('āœ… All text meets minimum size requirements'); } else { console.warn(`āŒ ${tooSmallCount} elements have text smaller than 14px`); } }, // Test image responsiveness testImages() { console.log('\nšŸ–¼ļø Testing Image Responsiveness...'); const images = document.querySelectorAll('img'); let responsiveCount = 0; images.forEach(img => { const style = window.getComputedStyle(img); if (style.maxWidth === '100%' || style.width === '100%') { responsiveCount++; } }); console.log(`āœ… ${responsiveCount}/${images.length} images are responsive`); if (responsiveCount < images.length) { console.warn(`āŒ ${images.length - responsiveCount} images may not be responsive`); } }, // Test sacred geometry performance on mobile testSacredGeometry() { console.log('\nšŸ”® Testing Sacred Geometry Performance...'); const geometry = document.querySelectorAll('.sacred-geometry, .global-sacred-geometry, .floating-sacred'); const screenWidth = window.innerWidth; geometry.forEach(element => { const style = window.getComputedStyle(element); const opacity = parseFloat(style.opacity); const transform = style.transform; if (screenWidth <= 480) { if (opacity <= 0.03) { console.log('āœ… Sacred geometry opacity optimized for small screens'); } else { console.warn('āŒ Sacred geometry opacity too high for mobile'); } if (transform.includes('scale') && transform.includes('0.')) { console.log('āœ… Sacred geometry scaled down for mobile'); } } }); }, // Test performance metrics testPerformance() { console.log('\n⚔ Testing Performance Metrics...'); if ('performance' in window) { const navigation = performance.getEntriesByType('navigation')[0]; const loadTime = navigation.loadEventEnd - navigation.loadEventStart; const domContentLoaded = navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart; console.log(`šŸ“Š Page load time: ${Math.round(loadTime)}ms`); console.log(`šŸ“Š DOM content loaded: ${Math.round(domContentLoaded)}ms`); if (loadTime < 3000) { console.log('āœ… Page load time is acceptable'); } else { console.warn('āŒ Page load time is slow'); } // Test FPS (simplified) let frameCount = 0; const startTime = performance.now(); function countFrames() { frameCount++; const elapsed = performance.now() - startTime; if (elapsed < 1000) { requestAnimationFrame(countFrames); } else { const fps = Math.round(frameCount * 1000 / elapsed); console.log(`šŸ“Š Approximate FPS: ${fps}`); if (fps >= 30) { console.log('āœ… Frame rate is acceptable'); } else { console.warn('āŒ Frame rate is low'); } } } requestAnimationFrame(countFrames); } }, // Test accessibility features testAccessibility() { console.log('\n♿ Testing Accessibility...'); // Check for alt text on images const images = document.querySelectorAll('img'); let imagesWithAlt = 0; images.forEach(img => { if (img.getAttribute('alt') !== null) { imagesWithAlt++; } }); console.log(`āœ… ${imagesWithAlt}/${images.length} images have alt text`); // Check for focus states const focusableElements = document.querySelectorAll('a, button, input, textarea, select'); console.log(`šŸ“Š ${focusableElements.length} focusable elements found`); // Check color contrast (simplified) const textElements = document.querySelectorAll('p, h1, h2, h3, h4, h5, h6, span, div'); let lowContrastCount = 0; textElements.forEach(element => { const style = window.getComputedStyle(element); const color = style.color; const backgroundColor = style.backgroundColor; // Simple contrast check (not comprehensive) if (color === 'rgb(128, 128, 128)' || color === '#808080') { lowContrastCount++; } }); if (lowContrastCount === 0) { console.log('āœ… No obvious low contrast text detected'); } else { console.warn(`āŒ ${lowContrastCount} elements may have low contrast`); } }, // Test mobile-specific features testMobileFeatures() { console.log('\nšŸ“± Testing Mobile-Specific Features...'); // Check for mobile optimizations script const mobileScript = document.querySelector('script[src*="mobile-optimizations.js"]'); if (mobileScript) { console.log('āœ… Mobile optimizations script loaded'); } else { console.warn('āŒ Mobile optimizations script missing'); } // Check for touch event handling if ('ontouchstart' in window) { console.log('āœ… Touch events supported'); } else { console.log('ā„¹ļø Touch events not supported (desktop)'); } // Check for device orientation support if ('orientation' in window) { console.log('āœ… Device orientation supported'); } else { console.log('ā„¹ļø Device orientation not supported'); } // Check for vibration API if ('vibrate' in navigator) { console.log('āœ… Vibration API supported'); } else { console.log('ā„¹ļø Vibration API not supported'); } }, // Test responsive breakpoints testBreakpoints() { console.log('\nšŸ“ Testing Responsive Breakpoints...'); const width = window.innerWidth; if (width <= 480) { console.log('šŸ“± Mobile (≤480px) - Testing mobile optimizations'); this.testMobileSpecific(); } else if (width <= 768) { console.log('šŸ“± Tablet (≤768px) - Testing tablet optimizations'); } else if (width <= 1024) { console.log('šŸ’» Small Desktop (≤1024px)'); } else { console.log('šŸ–„ļø Large Desktop (>1024px)'); } console.log(`šŸ“Š Current viewport: ${width}x${window.innerHeight}px`); }, testMobileSpecific() { // Test if sacred geometry is properly reduced const geometry = document.querySelector('.sacred-geometry'); if (geometry) { const style = window.getComputedStyle(geometry); const opacity = parseFloat(style.opacity); if (opacity <= 0.2) { console.log('āœ… Sacred geometry opacity reduced for mobile'); } else { console.warn('āŒ Sacred geometry too prominent on mobile'); } } // Test if complex animations are disabled const animations = document.querySelectorAll('.sacred-breathe, .sacred-spiral'); let animationsDisabled = 0; animations.forEach(element => { const style = window.getComputedStyle(element); if (style.animationName === 'none') { animationsDisabled++; } }); if (animationsDisabled > 0) { console.log('āœ… Complex animations disabled on mobile'); } }, // Generate mobile optimization report generateReport() { console.log('\nšŸ“‹ MOBILE OPTIMIZATION REPORT'); console.log('================================'); const issues = []; const successes = []; // Collect all console messages and categorize // This is a simplified version - in practice you'd track these during tests console.log('\nšŸ“Š Summary:'); console.log(`āœ… Optimizations working: ${successes.length}`); console.log(`āŒ Issues found: ${issues.length}`); if (issues.length === 0) { console.log('\nšŸŽ‰ All mobile optimizations are working correctly!'); } else { console.log('\nšŸ”§ Recommended fixes:'); issues.forEach((issue, index) => { console.log(`${index + 1}. ${issue}`); }); } }, // Run all tests runAllTests() { this.testViewport(); this.testResponsiveCSS(); this.testTouchTargets(); this.testFontSizes(); this.testImages(); this.testSacredGeometry(); this.testPerformance(); this.testAccessibility(); this.testMobileFeatures(); this.testBreakpoints(); setTimeout(() => { this.generateReport(); }, 2000); // Wait for performance tests to complete }, // Manual testing helpers simulateMobile() { console.log('šŸ“± Simulating mobile viewport...'); document.documentElement.style.width = '375px'; document.body.style.width = '375px'; console.log('Resize your browser to see mobile layout'); }, testTouch() { console.log('šŸ‘† Testing touch interactions...'); const event = new TouchEvent('touchstart', { bubbles: true, cancelable: true, touches: [{ clientX: 100, clientY: 100 }] }); document.dispatchEvent(event); console.log('Touch event simulated'); }, measureScrollPerformance() { console.log('šŸ“œ Measuring scroll performance...'); let scrollCount = 0; const startTime = performance.now(); const scrollHandler = () => { scrollCount++; const elapsed = performance.now() - startTime; if (elapsed > 1000) { const scrollsPerSecond = scrollCount / (elapsed / 1000); console.log(`šŸ“Š Scroll events per second: ${Math.round(scrollsPerSecond)}`); window.removeEventListener('scroll', scrollHandler); } }; window.addEventListener('scroll', scrollHandler); console.log('Scroll around the page to test performance'); } }; // Export to global scope for manual testing window.MobileTester = MobileTester; // Auto-run tests when script loads if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => MobileTester.init()); } else { MobileTester.init(); } // Add helper commands console.log('\nšŸ› ļø Mobile Testing Commands:'); console.log('MobileTester.simulateMobile() - Simulate mobile viewport'); console.log('MobileTester.testTouch() - Test touch interactions'); console.log('MobileTester.measureScrollPerformance() - Measure scroll performance'); console.log('MobileTester.runAllTests() - Run all tests again'); })();